This document aims at exploring the dataset of 4 individuals in 2018. For that purpose, we need first to load the weanlingNES package to load data.
# load library
library(weanlingNES)
# load data
data("data_nes", package = "weanlingNES")
# load("../data/data_nes.rda")
Let’s have a look at what’s inside data_nes$data_2018:
# list structure
str(data_nes$year_2018, max.level = 1, give.attr = F, no.list = T)
## $ ind_2018070:Classes 'data.table' and 'data.frame': 22393 obs. of 47 variables:
## $ ind_2018072:Classes 'data.table' and 'data.frame': 29921 obs. of 47 variables:
## $ ind_2018074:Classes 'data.table' and 'data.frame': 38608 obs. of 47 variables:
## $ ind_2018080:Classes 'data.table' and 'data.frame': 19028 obs. of 47 variables:
A list of 4 data.frames, one for each seal
For convenience, we aggregate all 4 individuals into one dataset.
# combine all individuals
data_2018 <- rbindlist(data_nes$year_2018)
# display
DT::datatable(data_2018[sample.int(.N, 10), ], options = list(scrollX = T))
Table 1: Sample of 10 random rows from data_2018
Summary
# raw_data
data_2018[, .(
nb_days_recorded = uniqueN(as.Date(date)),
nb_dives = .N,
maxdepth_mean = mean(maxdepth),
dduration_mean = mean(dduration),
botttime_mean = mean(botttime),
pdi_mean = mean(pdi, na.rm = T)
), by = .id] %>%
sable(
caption = "Summary diving information relative to each 2018 individual",
digits = 2
)
Table 2: Summary diving information relative to each 2018 individual
|
.id
|
nb_days_recorded
|
nb_dives
|
maxdepth_mean
|
dduration_mean
|
botttime_mean
|
pdi_mean
|
|
ind_2018070
|
232
|
22393
|
305.52
|
783.27
|
243.22
|
109.55
|
|
ind_2018072
|
341
|
29921
|
357.86
|
876.96
|
278.02
|
104.90
|
|
ind_2018074
|
372
|
38608
|
250.67
|
686.25
|
291.89
|
302.77
|
|
ind_2018080
|
215
|
19028
|
296.50
|
867.69
|
339.90
|
103.51
|
Very nice dataset :)
Some explanatory plots
Missing values
# build dataset to check for missing values
dataPlot <- melt(data_2018[, .(.id, is.na(.SD)), .SDcol = -c(
".id",
"divenumber",
"year",
"month",
"day",
"hour",
"min",
"sec",
"juldate",
"divetype",
"date",
"phase",
"lat",
"lon"
)])
# add the id of rows
dataPlot[, id_row := c(1:.N), by = c("variable", ".id")]
# plot
ggplot(dataPlot, aes(x = variable, y = id_row, fill = value)) +
geom_tile() +
labs(x = "Attributes", y = "Rows") +
scale_fill_manual(
values = c("white", "black"),
labels = c("Real", "Missing")
) +
facet_wrap(.id ~ ., scales = "free_y") +
theme_jjo() +
theme(
legend.position = "top",
axis.text.x = element_text(angle = 45, hjust = 1),
legend.key = element_rect(colour = "black")
)
So far so good, only few variables seems to have missing values:
# table with percent
table_inter <- data_2018[, lapply(.SD, function(x) {
round(length(x[is.na(x)]) * 100 / length(x), 1)
}), .SDcol = -c(
".id",
"divenumber",
"year",
"month",
"day",
"hour",
"min",
"sec",
"juldate",
"divetype",
"date",
"phase",
"lat",
"lon"
)]
# find which are different from 0
cond_inter <- sapply(table_inter, function(x) {
x == 0
})
# display the percentages that are over 0
table_inter[, which(cond_inter) := NULL] %>%
sable(caption = "Percentage of missing values per columns having missing values!") %>%
scroll_box(width = "100%")
Table 3: Percentage of missing values per columns having missing values!
|
lightatsurf
|
lattenuation
|
euphoticdepth
|
thermoclinedepth
|
driftrate
|
benthicdivevertrate
|
cornerindex
|
foragingindex
|
verticalspeed90perc
|
verticalspeed95perc
|
dist_dep
|
|
26.3
|
89
|
62.6
|
1.3
|
0.5
|
22.7
|
75.8
|
0.5
|
0.1
|
0.1
|
35.1
|
Outliers
Ok, let’s have a look at all the data. But first, we have to remove outliers. Some of them are quiet easy to spot looking at the distribution of dive duration:
Before
ggplot(
data_2018[, .SD][, state := "Before"],
aes(x = dduration, fill = .id)
) +
geom_histogram(show.legend = FALSE) +
geom_vline(xintercept = 3000, linetype = "longdash") +
facet_grid(state ~ .id,
scales = "free"
) +
labs(y = "# of dives", x = "Dive duration (s)") +
theme_jjo()
After
ggplot(
data_2018[dduration < 3000, ][][, state := "After"],
aes(x = dduration, fill = .id)
) +
geom_histogram(show.legend = FALSE) +
geom_vline(xintercept = 3000, linetype = "longdash") +
facet_grid(state ~ .id,
scales = "free"
) +
labs(x = "# of dives", y = "Dive duration (s)") +
theme_jjo()
It seems much better, so let’s remove any rows with dduration > 3000 sec.
# filter data
data_2018_filter <- data_2018[dduration < 3000, ]
# nbrow removed
data_2018[dduration >= 3000, .(nb_row_removed = .N), by = .id] %>%
sable(caption = "# of rows removed by 2018-individuals")
Table 4: # of rows removed by 2018-individuals
|
.id
|
nb_row_removed
|
|
ind_2018070
|
3
|
|
ind_2018072
|
1
|
|
ind_2018074
|
33
|
Check day and night
Light levels
# let's first average `lightatsurf` by individuals, day since departure and hour
dataPlot <- data_2018[, .(lightatsurf = median(lightatsurf)),
by = .(.id, day_departure, date = as.Date(date), hour)
]
# display the result
ggplot(dataPlot, aes(x = day_departure, y = hour, fill = lightatsurf)) +
geom_tile() +
facet_grid(.id ~ .) +
theme_jjo() +
labs(x = "# of days since departure",
y = "Hour",
fill = "Light level at the surface")+
theme(legend.position = c("bottom"))
Day and night detection
# let's first average `lightatsurf` by individuals, day since departure and hour
dataPlot <- data_2018[, .(lightatsurf = median(lightatsurf)),
by = .(.id,
day_departure,
date = as.Date(date),
hour,
phase)
]
# display the result
ggplot(dataPlot, aes(x = day_departure, y = hour, fill = phase)) +
geom_tile() +
facet_grid(.id ~ .) +
theme_jjo() +
labs(x = "# of days since departure",
y = "Hour",
fill = "Day time and night time as detected by the `cal_phase_day` function") +
theme(legend.position = c("bottom"))
All Variables
names_display <- names(data_2018_filter[, -c(
".id",
"date",
"divenumber",
"year",
"month",
"day",
"hour",
"min",
"sec",
"juldate",
"divetype",
"euphoticdepth",
"thermoclinedepth",
"day_departure",
"phase",
"lat",
"lon",
"dist_dep"
)])
for (i in names_display) {
cat("#####", i, "{.unlisted .unnumbered} \n")
if (i == "maxdepth") {
print(
ggplot() +
geom_point(
data = data_2018_filter[, .(
.id,
date,
thermoclinedepth
)],
aes(
x = as.Date(date),
y = -thermoclinedepth,
colour = "Thermocline (m)"
),
alpha = .2,
size = .5
) +
geom_point(
data = data_2018_filter[, .(
.id,
date,
euphoticdepth
)],
aes(
x = as.Date(date),
y = -euphoticdepth,
colour = "Euphotic (m)"
),
alpha = .2,
size = .5
) +
scale_colour_manual(
values = c(
"Thermocline (m)" = "red",
"Euphotic (m)" = "black"
),
name = "Zone"
) +
new_scale_color() +
geom_point(
data = melt(data_2018_filter[, .(.id, date, get(i))],
id.vars = c(".id", "date")),
aes(
x = as.Date(date),
y = -value,
col = .id
),
alpha = 1 / 10,
size = .5,
show.legend = FALSE
) +
facet_wrap(. ~ .id, scales = "free") +
scale_x_date(date_labels = "%m/%Y") +
labs(x = "Date", y = "Maximum Depth (m)") +
theme_jjo() +
theme(
axis.text.x = element_text(angle = 45, hjust = 1),
legend.position = "bottom"
)
)
cat("<blockquote> Considering `ind_2018074` has slightly different values than other individuals for the thermocline depth, it would be interesting to see where the animal went. </blockquote>")
} else if (i == "driftrate") {
print(
ggplot(
data = melt(data_2018_filter[, .(.id, date, get(i), divetype)],
id.vars = c(".id", "date", "divetype")),
aes(
x = as.Date(date),
y = value,
col = divetype
)
) +
geom_point(
alpha = 1 / 10,
size = .5
) +
facet_wrap(. ~ .id, scales = "free") +
scale_x_date(date_labels = "%m/%Y") +
labs(x = "Date", y = "Drift Rate 'm/s", col = "Dive Type") +
theme_jjo() +
theme(
axis.text.x = element_text(angle = 45, hjust = 1),
legend.position = "bottom"
) +
guides(colour = guide_legend(override.aes = list(
size = 7,
alpha = 1
)))
)
} else {
print(
ggplot(
data = melt(data_2018_filter[, .(.id, date, get(i))],
id.vars = c(".id", "date")),
aes(
x = as.Date(date),
y = value,
col = .id
)
) +
geom_point(
show.legend = FALSE,
alpha = 1 / 10,
size = .5
) +
facet_wrap(. ~ .id, scales = "free") +
scale_x_date(date_labels = "%m/%Y") +
labs(x = "Date", y = i) +
theme_jjo() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
)
}
cat("\n \n")
}
maxdepth
Considering ind_2018074 has slightly different values than other individuals for the thermocline depth, it would be interesting to see where the animal went.
dduration

botttime

desctime

descrate

asctime

ascrate

pdi

dwigglesdesc

dwigglesbott

dwigglesasc

totvertdistbot

bottrange

efficiency

idz

lightatbott

lwiggles

lightatsurf

lattenuation

tempatsurf

tempatbott

driftdiveindex

driftrate

benthicdiveindex

benthicdivevertrate

cornerindex

foragingindex

verticalspeed90perc

verticalspeed95perc

Few questions, that I should look into it:
- is the bimodal distribution of
dduration, desctime due to nycthemeral migration?
- is the bimodal distribution of
descrate (especially for ind2018070 and ind_2018072) due to drift dive?
- is
lightatbott could be used to identify bioluminescence, cause it seems there is a lot going on at the bottom?
- are the variations observed for
lightatsurf is due to moon cycle?
- not sure why is there a bimodal distribution of
tempatbott!
drifrate that one is awesome! Thanks to divetype we can clearly see a pattern of how driftrate (and so buoyancy) change according time.
- the bimodal distribution of
verticalspeed90 and verticalspeed95 should be due to drift dive.
# same plot with a colored for the phase of the day
for (i in names_display) {
cat("####", i, "{-} \n")
print(
ggplot(
data = melt(data_2018_filter[, .(.id, date, get(i), phase)],
id.vars = c(
".id",
"date",
"phase"
)
),
aes(
x = as.Date(date),
y = value,
col = phase
)
) +
geom_point(
alpha = 1 / 10,
size = .5
) +
facet_wrap(. ~ .id, scales = "free") +
scale_x_date(date_labels = "%m/%Y") +
labs(x = "Date", y = i) +
theme_jjo() +
theme(
axis.text.x = element_text(angle = 45, hjust = 1),
legend.position = "bottom"
) +
guides(colour = guide_legend(override.aes = list(
size = 7,
alpha = 1
)))
)
cat("\n \n")
}
maxdepth

dduration

botttime

desctime

descrate

asctime

ascrate

pdi

dwigglesdesc

dwigglesbott

dwigglesasc

totvertdistbot

bottrange

efficiency

idz

lightatbott

lwiggles

lightatsurf

lattenuation

tempatsurf

tempatbott

driftdiveindex

driftrate

benthicdiveindex

benthicdivevertrate

cornerindex

foragingindex

verticalspeed90perc

verticalspeed95perc

All Variables during the first month
for (i in names_display) {
cat("####", i, "{.unlisted .unnumbered} \n")
if (i == "maxdepth") {
print(
ggplot() +
geom_point(
data = data_2018_filter[day_departure < 32, .(
.id,
day_departure,
thermoclinedepth
)],
aes(
x = day_departure,
y = -thermoclinedepth,
colour = "Thermocline (m)",
group = day_departure
),
alpha = .2,
size = .5
) +
geom_point(
data = data_2018_filter[day_departure < 32, .(
.id,
day_departure,
euphoticdepth
)],
aes(
x = day_departure,
y = -euphoticdepth,
colour = "Euphotic (m)",
group = day_departure
),
alpha = .2,
size = .5
) +
scale_colour_manual(
values = c(
"Thermocline (m)" = "red",
"Euphotic (m)" = "black"
),
name = "Zone"
) +
new_scale_color() +
geom_boxplot(
data = melt(data_2018_filter[day_departure < 32,
.(.id, day_departure, get(i))],
id.vars = c(".id", "day_departure")),
aes(
x = day_departure,
y = -value,
col = .id,
group = day_departure
),
alpha = 1 / 10,
size = .5,
show.legend = FALSE
) +
facet_wrap(. ~ .id, scales = "free") +
labs(x = "# days since departure", y = "Maximum Depth (m)") +
theme_jjo() +
theme(legend.position = "bottom")
)
} else {
print(
ggplot(
data = melt(data_2018_filter[day_departure < 32,
.(.id, day_departure, get(i))],
id.vars = c(".id", "day_departure")),
aes(
x = day_departure,
y = value,
color = .id,
group = day_departure
)
) +
geom_boxplot(
show.legend = FALSE,
alpha = 1 / 10,
size = .5
) +
facet_wrap(. ~ .id, scales = "free") +
labs(x = "# days since departure", y = i) +
theme_jjo()
)
}
cat("\n \n")
}
maxdepth

dduration

botttime

desctime

descrate

asctime

ascrate

pdi

dwigglesdesc

dwigglesbott

dwigglesasc

totvertdistbot

bottrange

efficiency

idz

lightatbott

lwiggles

lightatsurf

lattenuation

tempatsurf

tempatbott

driftdiveindex

driftrate

benthicdiveindex

benthicdivevertrate

cornerindex

foragingindex

verticalspeed90perc

verticalspeed95perc

for (i in names_display) {
cat("####", i, "{.unlisted .unnumbered} \n")
print(
ggplot(
data = melt(data_2018_filter[
day_departure < 32,
.(.id, day_departure, get(i), phase)
],
id.vars = c(".id", "day_departure", "phase")
),
aes(
x = day_departure,
y = value,
color = phase,
group = interaction(day_departure, phase),
)
) +
geom_boxplot(
alpha = 1 / 10,
size = .5
) +
facet_wrap(. ~ .id, scales = "free") +
labs(x = "# days since departure", y = i) +
theme_jjo() +
theme(legend.position = "bottom")
)
cat("\n \n")
}
maxdepth

dduration

botttime

desctime

descrate

asctime

ascrate

pdi

dwigglesdesc

dwigglesbott

dwigglesasc

totvertdistbot

bottrange

efficiency

idz

lightatbott

lwiggles

lightatsurf

lattenuation

tempatsurf

tempatbott

driftdiveindex

driftrate

benthicdiveindex

benthicdivevertrate

cornerindex

foragingindex

verticalspeed90perc

verticalspeed95perc

Correlation
Can we find nice correlation?
# compute correlation
corr_2018 <- round(cor(data_2018_filter[, names_display, with = F],
use = "pairwise.complete.obs"
), 1)
# replace NA value by 0
corr_2018[is.na(corr_2018)] <- 0
# compute p_values
corr_p_2018 <- cor_pmat(data_2018_filter[, names_display, with = F])
# replace NA value by 0
corr_p_2018[is.na(corr_p_2018)] <- 1
# display
ggcorrplot(
corr_2018,
p.mat = corr_p_2018,
hc.order = TRUE,
method = "circle",
type = "lower",
ggtheme = theme_jjo(),
sig.level = 0.05,
colors = c("#00AFBB", "#E7B800", "#FC4E07")
)
Another way to see it:
# flatten correlation matrix
cor_result_2018 <- flat_cor_mat(corr_2018, corr_p_2018)
# keep only the one above .7
cor_result_2018[cor >= .7, ][order(-abs(cor))] %>%
sable(caption = "Pairwise correlation above 0.75 and associated p-values")
Table 5: Pairwise correlation above 0.75 and associated p-values
|
row
|
column
|
cor
|
p
|
|
verticalspeed90perc
|
verticalspeed95perc
|
1.0
|
0
|
|
maxdepth
|
asctime
|
0.8
|
0
|
|
botttime
|
efficiency
|
0.8
|
0
|
|
dwigglesbott
|
foragingindex
|
0.8
|
0
|
|
maxdepth
|
dduration
|
0.7
|
0
|
|
maxdepth
|
desctime
|
0.7
|
0
|
|
dduration
|
desctime
|
0.7
|
0
|
|
dduration
|
asctime
|
0.7
|
0
|
|
totvertdistbot
|
bottrange
|
0.7
|
0
|
|
totvertdistbot
|
verticalspeed90perc
|
0.7
|
0
|
|
totvertdistbot
|
verticalspeed95perc
|
0.7
|
0
|
I guess nothing unexpected here, I’ll have to check with Patrick about the efficiency ;)
Dive Type
# dataset to plot proportional area plot
data_2018_filter[, sum_id := .N, by = .(.id, day_departure)] %>%
.[, sum_id_days := .N, by = .(.id, day_departure, divetype)] %>%
.[, prop := sum_id_days / sum_id]
dataPlot <- unique(data_2018_filter[, .(prop, .id, divetype, day_departure)])
# area plot
ggplot(dataPlot, aes(
x = as.numeric(day_departure),
y = prop,
fill = as.character(divetype)
)) +
geom_area(alpha = 0.6, size = 1) +
facet_wrap(.id ~ ., scales = "free") +
theme_jjo() +
theme(legend.position = "bottom") +
labs(x = "# of days since departure",
y = "Proportion of dives",
fill = "Dive types")
Dive duration vs. Maximum depth
Colored by ID
# plot
ggplot(data = data_2018_filter, aes(y = dduration, x = maxdepth, col = .id)) +
geom_point(size = .5, alpha = .1, show.legend = FALSE) +
facet_wrap(.id ~ .) +
labs(x = "Maximum depth (m)", y = "Dive duration (s)") +
theme_jjo()
Colored by Dive Type
# plot
ggplot(data = data_2018_filter, aes(y = dduration,
x = maxdepth,
col = divetype)) +
geom_point(size = .5, alpha = .1) +
facet_wrap(.id ~ .) +
guides(colour = guide_legend(override.aes = list(size = 5, alpha = 1))) +
labs(x = "Maximum depth (m)", y = "Dive duration (s)") +
theme_jjo() +
theme(legend.position = "bottom")
Colored by # days since departure
# plot
ggplot(data = data_2018_filter[, prop_track := (day_departure * 100) / max(day_departure), by = .id],
aes(y = dduration, x = maxdepth, col = prop_track)) +
geom_point(size = .5, alpha = .1) +
facet_wrap(.id ~ .) +
labs(x = "Maximum depth (m)",
y = "Dive duration (s)",
col = "Proportion of completed track (%)") +
scale_color_continuous(type = "viridis") +
theme_jjo() +
theme(legend.position = "bottom")
Colored by phases of day
# plot
ggplot(data = data_2018_filter, aes(y = dduration, x = maxdepth, col = phase)) +
geom_point(size = .5, alpha = .1) +
facet_wrap(.id ~ .) +
guides(colour = guide_legend(override.aes = list(size = 5, alpha = 1))) +
labs(x = "Maximum depth (m)",
y = "Dive duration (s)",
col = "Phases of the day") +
theme_jjo() +
theme(legend.position = "bottom")
There seems to be a patch for high depths (especially visible for ind2018070), but I don’t know what it could be linked to…
Drift Rate
In the following graphs:
driftrate is calculated using only divetype == "2: drift"
- whereas all the others variables are calculated all dives considered
# build dataset
dataPlot <- data_2018_filter[divetype == "2: drift",
# median drift rate for drift dive
.(driftrate = median(driftrate, na.rm = T)),
by = .(.id, day_departure)
][data_2018_filter[,
.(
# median dive duration all dives considered
dduration = median(dduration, na.rm = T),
# median max depth all dives considered
maxdepth = median(maxdepth, na.rm = T),
# median bottom dives all dives considered
botttime = median(botttime, na.rm = T)
),
by = .(.id, day_departure)
],
on = c(".id", "day_departure")
]
# plot
ggplot(dataPlot, aes(x = botttime, y = driftrate, col = .id)) +
geom_point(size = .5, alpha = .5) +
geom_smooth(method = "lm") +
guides(color = "none") +
facet_wrap(.id ~ .) +
scale_x_continuous(limits = c(0, 700)) +
labs(x = "Daily median Bottom time (s)",
y = "Daily median drift rate (m.s-1)") +
theme_jjo()
# plot
ggplot(dataPlot, aes(x = maxdepth, y = driftrate, col = .id)) +
geom_point(size = .5, alpha = .5) +
geom_smooth(method = "lm") +
guides(color = "none") +
facet_wrap(.id ~ .) +
labs(x = "Daily median Maximum depth (m)",
y = "Daily median drift rate (m.s-1)") +
theme_jjo()
# plot
ggplot(dataPlot, aes(x = dduration, y = driftrate, col = .id)) +
geom_point(size = .5, alpha = .5) +
geom_smooth(method = "lm") +
guides(color = "none") +
facet_wrap(.id ~ .) +
labs(x = "Daily median Dive duration (s)",
y = "Daily median drift rate (m.s-1)") +
theme_jjo()
Behavioral Aerobic Dive Limit (bADL)
# dive duration vs pdi by days
ggplot(data = data_2018_filter[pdi < 300, ], aes(
x = dduration,
y = pdi,
color = .id,
group = dduration,
fill = "none"
)) +
geom_boxplot(show.legend = FALSE, outlier.alpha = 0.05, alpha = 0) +
labs(x = "Dive duration (s)", y = "Post-dive duration (s)") +
facet_wrap(. ~ .id, scales = "free_x") +
theme_jjo()
# dive duration vs pdi by days
ggplot(data = data_2018_filter[pdi < 300,], aes(x = dduration,
y = pdi,
color = .id)) +
geom_point(show.legend = FALSE, alpha = 0.05) +
geom_smooth(
method = "gam",
show.legend = FALSE,
col = "black",
linetype = "dashed"
) +
labs(x = "Dive duration (s)", y = "Post-dive duration (s)") +
facet_wrap(. ~ .id, scales = "free_x") +
theme_jjo()
# dive duration vs pdi by days
ggplot(
data = data_2018_filter[pdi < 300, .(.id, pdi_ratio = pdi / dduration, day_departure)],
aes(
x = day_departure,
y = pdi_ratio,
color = .id,
group = day_departure,
fill = "none"
)
) +
geom_boxplot(show.legend = FALSE,
outlier.alpha = 0.05,
alpha = 0) +
labs(x = "# days since departure", y = "Post-dive / Dive duration ratio") +
facet_wrap(. ~ .id, scales = "free_x") +
# zoom
coord_cartesian(ylim = c(0, 0.4)) +
theme_jjo()
Based on Shero et al. (2018), we decided to look at the bADL as the 95th percentile of dive duration each day, for those with \(n \geq 50\). This threshold was chosen following this figure:
ggplot(data_2018_filter[,.(nb_dives = .N),
by = .(.id, day_departure)],
aes(x=nb_dives, fill=.id)) +
geom_histogram(show.legend = FALSE) +
facet_grid(.~.id) +
labs(y="# of days", x = "# of dives per day") +
theme_jjo()
# select day that have at least 50 dives
days_to_keep = data_2018_filter[,
.(nb_dives = .N),
by = .(.id, day_departure)] %>%
.[nb_dives >= 50,]
# keep only those days
data_2018_filter_complete_day = merge(data_2018_filter,
days_to_keep,
by = c(".id", "day_departure"))
# data plot
dataPlot = data_2018_filter_complete_day[,
.(badl = quantile(dduration, 0.95)),
by = .(.id, day_departure)]
# combine two datasets to be able to use a second axis
# https://stackoverflow.com/questions/49185583/two-y-axes-with-different-scales-for-two-datasets-in-ggplot2
dataMegaPlot = rbind(data_2018_filter_complete_day[divetype == "2: drift"] %>%
.[, .(w = .id,
y = driftrate,
x = day_departure,
z = "second_plot")],
dataPlot[, .(
w = .id,
# tricky one
y = (badl / 1000) - 1,
x = day_departure,
z = "first_plot"
)])
# plot
ggplot() +
geom_point(
data = dataMegaPlot[z == "second_plot", ],
aes(x = x, y = y),
alpha = 1 / 10,
size = 0.5,
color = "grey40",
show.legend = FALSE
) +
geom_path(data = dataMegaPlot[z == "first_plot", ],
aes(x = x, y = y, color = w),
show.legend = FALSE) +
scale_y_continuous(
# Features of the first axis
name = "Drift rate (m/s)",
# Add a second axis and specify its features
sec.axis = sec_axis( ~ (. * 1000) + 1000,
name = "Behavioral Aerobic Dive Limit (s)")
) +
labs(x = "# days since departure") +
facet_wrap(w ~ .) +
theme_jjo()
Looking at this graph, I want to believe that there is some kind of relationship between the bADL as defined by Shero et al. (2018) and the drift rate (and so buyoancy).
# get badl
dataplot_1 = data_2018_filter_complete_day[,
.(badl = quantile(dduration, 0.95)),
by = .(.id, day_departure)]
# get driftrate
dataplot_2 = data_2018_filter_complete_day[divetype == "2: drift",
.(driftrate = median(driftrate)),
by = .(.id, day_departure)]
# merge
dataPlot = merge(dataplot_1,
dataplot_2,
by = c(".id", "day_departure"),
all = TRUE)
# plot
ggplot(data = dataPlot, aes(x = badl, y = driftrate, col = .id)) +
geom_point(show.legend = FALSE) +
facet_wrap(.id~., scales = "free") +
theme_jjo()

ind_2018070
# ind_2018070
plot_ly(
x = dataPlot[.id == "ind_2018070", badl],
y = dataPlot[.id == "ind_2018070", day_departure],
z = dataPlot[.id == "ind_2018070", driftrate],
type = "scatter3d",
mode = "markers",
marker = list(size = 2),
color = dataPlot[.id == "ind_2018070", day_departure]
) %>%
layout(scene = list(xaxis = list(title = 'Behavioral ADL'),
yaxis = list(title = '# days since departure'),
zaxis = list(title = 'Drift rate (m/s)')))
ind_2018072
# ind_2018072
plot_ly(
x = dataPlot[.id == "ind_2018072", badl],
y = dataPlot[.id == "ind_2018072", day_departure],
z = dataPlot[.id == "ind_2018072", driftrate],
type = "scatter3d",
mode = "markers",
marker = list(size = 2),
color = dataPlot[.id == "ind_2018072", day_departure]
) %>%
layout(scene = list(xaxis = list(title = 'Behavioral ADL'),
yaxis = list(title = '# days since departure'),
zaxis = list(title = 'Drift rate (m/s)')))
ind_2018074
# ind_2018074
plot_ly(
x = dataPlot[.id == "ind_2018074", badl],
y = dataPlot[.id == "ind_2018074", day_departure],
z = dataPlot[.id == "ind_2018074", driftrate],
type = "scatter3d",
mode = "markers",
marker = list(size = 2),
color = dataPlot[.id == "ind_2018074", day_departure]
) %>%
layout(scene = list(xaxis = list(title = 'Behavioral ADL'),
yaxis = list(title = '# days since departure'),
zaxis = list(title = 'Drift rate (m/s)')))
ind_2018072
# ind_2018080
plot_ly(
x = dataPlot[.id == "ind_2018080", badl],
y = dataPlot[.id == "ind_2018080", day_departure],
z = dataPlot[.id == "ind_2018080", driftrate],
type = "scatter3d",
mode = "markers",
marker = list(size = 2),
color = dataPlot[.id == "ind_2018080", day_departure]
) %>%
layout(scene = list(xaxis = list(title = 'Behavioral ADL'),
yaxis = list(title = '# days since departure'),
zaxis = list(title = 'Drift rate (m/s)')))
GPS data
# This piece of code is only there to show how to draw a polylines with a
# gradient color using leaflet.We're not using it due to the size of the
# created map, and will continue using circle marker
# datasets used to display map
df_driftrate = unique(data_2018_filter[.id == "ind_2018070" &
divetype == "2: drift",
.(.id, lat, lon, dduration)])
# color palette
pal <- colorNumeric(
palette = "YlGnBu",
domain = df_driftrate$dduration
)
# add
df_driftrate[, `:=`(nextLat = shift(lat),
nextLon = shift(lon),
color = pal(df_driftrate$dduration))]
# interactive map
gradient_map <- leaflet() %>%
setView(lng = -122, lat = 38, zoom = 2) %>%
addTiles()
# add lines
for (i in 1:nrow(df_driftrate)) {
gradient_map <- addPolylines(
map = gradient_map,
data = df_driftrate,
lat = as.numeric(df_driftrate[i, c('lat', 'nextLat')]),
lng = as.numeric(df_driftrate[i, c('lon', 'nextLon')]),
color = df_driftrate[i, color],
weight = 3,
group = "individual_1"
)
}
# add layer control
gradient_map <- addLayersControl(
map = gradient_map,
overlayGroups = c("individual_1"),
options = layersControlOptions(collapsed = FALSE)
)
# format(object.size(gradient_map), units = "Mb")
Because for some data the contrast in changes was not enough marked, the only treatment applied on these data is to remove outliers for each variable using the interquartile range rule.
# interactive map
gradient_map <- leaflet() %>%
setView(lng = -132, lat = 48, zoom = 4) %>%
addTiles()
# loop by individuals and variable
grps = NULL
for (i in seq(data_2018_filter[!is.na(lat),unique(.id)])){
for (k in c("dduration","maxdepth","efficiency", "driftrate")){
if (k == "driftrate"){
# set dataset used to plot
dataPlot = unique(data_2018_filter %>%
.[order(date),] %>%
.[.id==data_2018_filter[!is.na(lat), unique(.id)][i] &
divetype == "2: drift" &
!is.na(get(k)),
c("lat", "lon", k), with=FALSE] %>%
.[!is_outlier(get(k)),])
# color palette creation
colPal <- colorNumeric(
palette = "BrBG",
domain = seq(-dataPlot[,max(abs(driftrate))],
dataPlot[,max(abs(driftrate))],
0.1)
)
} else {
# set dataset used to plot
dataPlot = unique(data_2018_filter %>%
.[order(date),] %>%
.[.id==data_2018_filter[!is.na(lat), unique(.id)][i] &
divetype != "2: drift" &
!is.na(get(k)),
c("lat", "lon", k), with=FALSE] %>%
.[!is_outlier(get(k)),])
# color palette creation
colPal <- colorNumeric(
palette = "YlGnBu",
domain = dataPlot[,get(k)]
)
}
# add color to dataset
dataPlot[, color := colPal(dataPlot[,get(k)])]
# add size column
dataPlot[, radius := 3]
# mark the beginning of the trip
dataPlot[1, `:=` (color = "green",
radius = 4)]
# mark the end of the trip
dataPlot[.N, `:=` (color = "red",
radius = 4)]
# reorder to make the end and the beginning in front
dataPlot = rbind(dataPlot[-1,],dataPlot[1,])
# add markers to map
gradient_map <- addCircleMarkers(
map = gradient_map,
data = dataPlot,
lat = ~lat,
lng = ~lon,
radius = ~radius,
stroke = FALSE,
color = ~color,
fillOpacity = 1,
group = paste(data_2018_filter[,unique(.id)][i], "-", k)
) %>%
addLegend("bottomleft",
data = dataPlot,
group = paste(data_2018_filter[,unique(.id)][i], "-", k),
pal = colPal,
values = ~get(k),
title = k,
opacity = 1
)
# retrieve groups
grps = c(grps, paste(data_2018_filter[,unique(.id)][i], "-", k))
}
}
# add layer control
gradient_map <- addLayersControl(
map = gradient_map,
overlayGroups = grps,
options = layersControlOptions(collapsed = TRUE)
) %>% hideGroup(grps)
# display
gradient_map
LS0tCnRpdGxlOiAiRGF0YSBFeHBsb3JhdGlvbiAtIDIwMTgiCmF1dGhvcjogIkpvZmZyZXkgSk9VTUFBIgpkYXRlOiAiYHIgaW52aXNpYmxlKFN5cy5zZXRsb2NhbGUobG9jYWxlID0gJ0MnKSk7IGZvcm1hdChTeXMuRGF0ZSgpLCBmb3JtYXQgPSAnJUIgJWQsICVZJylgIgpvdXRwdXQ6CiAgYm9va2Rvd246Omh0bWxfZG9jdW1lbnQyOgogICAgY3NzOiBjb3Ntb19jdXN0b20uY3NzCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBkZl9wcmludDogZGVmYXVsdAogICAgZmlnX2NhcHRpb246IHllcwogICAgY29kZV9kb3dubG9hZDogeWVzCiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IHllcwogICAgICBzbW9vdGhfc2Nyb2xsOiBubwp2aWduZXR0ZTogPgogICVcVmlnbmV0dGVJbmRleEVudHJ5e0RhdGEgRXhwbG9yYXRpb24gLSAyMDE4fQogICVcVmlnbmV0dGVFbmdpbmV7a25pdHI6OnJtYXJrZG93bn0KICAlXFZpZ25ldHRlRW5jb2Rpbmd7VVRGLTh9Ci0tLQogIApgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KIyBjb21tYW5kIHRvIGJ1aWxkIHBhY2thZ2Ugd2l0aG91dCBnZXR0aW5nIHZpZ25ldHRlIGVycm9yCiMgaHR0cHM6Ly9naXRodWIuY29tL3JzdHVkaW8vcmVudi9pc3N1ZXMvODMzCiMgZGV2dG9vbHM6OmNoZWNrKGJ1aWxkX2FyZ3M9YygiLS1uby1idWlsZC12aWduZXR0ZXMiKSkKCiMgcmVkdWNlIHBuZyBzaXplCmtuaXRyOjprbml0X2hvb2tzJHNldChvcHRpcG5nID0ga25pdHI6Omhvb2tfb3B0aXBuZykKa25pdHI6OmtuaXRfaG9va3Mkc2V0KHBuZ3F1YW50ID0ga25pdHI6Omhvb2tfcG5ncXVhbnQpCgojIGdsb2JhbCBvcHRpb24gcmVsYXRpdmUgdG8gcm1hcmtkb3duCmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICBlY2hvID0gVFJVRSwKICBmaWcuYWxpZ24gPSAiY2VudGVyIiwKICBvdXQud2lkdGggPSAiMTAwJSIsCiAgbWVzc2FnZSA9IEZBTFNFLAogIHdhcm5pbmcgPSBGQUxTRSwKICAjIHRpZHkgPSBUUlVFLAogIG9wdGlwbmcgPSAiLW83IC1xdWlldCIsCiAgcG5ncXVhbnQgPSAiLS1zcGVlZD0xIgopCgojIGxpYnJhcnkKbGlicmFyeShkYXRhLnRhYmxlKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoa2FibGVFeHRyYSkKbGlicmFyeShsZWFmbGV0KQpsaWJyYXJ5KGd0c3VtbWFyeSkgIyBodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvZ3RzdW1tYXJ5L3ZpZ25ldHRlcy90Ymxfc3VtbWFyeS5odG1sCmxpYnJhcnkoY29ycnBsb3QpCmxpYnJhcnkoZ2djb3JycGxvdCkKbGlicmFyeShnZ25ld3NjYWxlKQpsaWJyYXJ5KG1hZ3JpdHRyKQpsaWJyYXJ5KERUKQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeShnZW9zcGhlcmUpCgojIHJlbW92ZSBzb21lIHdhcm5pbmdzCnN1cHByZXNzV2FybmluZ3MobGlicmFyeShnZ3Bsb3QyKSkKCiMgZGVmaW5lIG15IG93biB0YWJsZSBmb3JtYXQ6IGh0dHBzOi8vZ2l0aHViLmNvbS9oYW96aHUyMzMva2FibGVFeHRyYS9pc3N1ZXMvMzc0CnNhYmxlIDwtIGZ1bmN0aW9uKHgsIGVzY2FwZSA9IFQsIC4uLikgewogIGtuaXRyOjprYWJsZSh4LCBlc2NhcGUgPSBlc2NhcGUsIC4uLikgJT4lCiAgICBrYWJsZV9zdHlsaW5nKAogICAgICBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiLCAicmVzcG9uc2l2ZSIpLAogICAgICBmdWxsX3dpZHRoID0gRgogICAgKQp9CgojIHRoZW1lIGdncGxvdAojIGJhc2VkOiBodHRwczovL2JlbmphbWlubG91aXMtc3RhdC5mci9lbi9ibG9nLzIwMjAtMDUtMjEtYXN0dWNlcy1nZ3Bsb3Qtcm1hcmtkb3duLwp0aGVtZV9qam8gPC0gZnVuY3Rpb24oYmFzZV9zaXplID0gMTIpIHsKICB0aGVtZV9idyhiYXNlX3NpemUgPSBiYXNlX3NpemUpICUrcmVwbGFjZSUKICAgIHRoZW1lKAogICAgICAjIHRoZSB3aG9sZSBmaWd1cmUKICAgICAgIyBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMSksIGZhY2UgPSAiYm9sZCIsIG1hcmdpbiA9IG1hcmdpbigwLDAsNSwwKSwgaGp1c3QgPSAwKSwKICAgICAgIyBmaWd1cmUgYXJlYQogICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICMgYXhlcwogICAgICAjIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHJlbCgwLjg1KSwgZmFjZSA9ICJib2xkIiksCiAgICAgICMgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMC43MCksIGZhY2UgPSAiYm9sZCIpLAogICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiYmxhY2siLCBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMC4yLCAibGluZXMiKSwgdHlwZSA9ICJjbG9zZWQiKSksCiAgICAgICMgbGVnZW5kCiAgICAgICMgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMC44NSksIGZhY2UgPSAiYm9sZCIpLAogICAgICAjIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMC43MCksIGZhY2UgPSAiYm9sZCIpLAogICAgICAjIGxlZ2VuZC5rZXkgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BKSwKICAgICAgIyBsZWdlbmQua2V5LnNpemUgPSB1bml0KDEuNSwgImxpbmVzIiksCiAgICAgICMgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BKSwKICAgICAgIyBMZXMgPFUrMDBFOT50aXF1ZXR0ZXMgZGFucyBsZSBjYXMgZCd1biBmYWNldHRpbmcKICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiM4ODg4ODgiLCBjb2xvciA9ICIjODg4ODg4IiksCiAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHJlbCgwLjg1KSwgZmFjZSA9ICJib2xkIiwgY29sb3IgPSAid2hpdGUiLCBtYXJnaW4gPSBtYXJnaW4oNSwgMCwgNSwgMCkpCiAgICApCn0KYGBgCgojIyB7LnVubnVtYmVyZWR9CgpUaGlzIGRvY3VtZW50IGFpbXMgYXQgZXhwbG9yaW5nIHRoZSBkYXRhc2V0IG9mIDQgaW5kaXZpZHVhbHMgaW4gMjAxOC4gRm9yIHRoYXQgcHVycG9zZSwgd2UgbmVlZCBmaXJzdCB0byBsb2FkIHRoZSBgd2VhbmxpbmdORVNgIHBhY2thZ2UgdG8gbG9hZCBkYXRhLgoKYGBge3IgZGF0YS1leHBsb3JhdGlvbi0yMDE4LTF9CiMgbG9hZCBsaWJyYXJ5CmxpYnJhcnkod2VhbmxpbmdORVMpCgojIGxvYWQgZGF0YQpkYXRhKCJkYXRhX25lcyIsIHBhY2thZ2UgPSAid2VhbmxpbmdORVMiKQojIGxvYWQoIi4uL2RhdGEvZGF0YV9uZXMucmRhIikKYGBgCgpMZXTigJlzIGhhdmUgYSBsb29rIGF0IHdoYXTigJlzIGluc2lkZSBgZGF0YV9uZXMkZGF0YV8yMDE4YDoKICAKYGBge3IgZGF0YS1leHBsb3JhdGlvbi0yMDE4LTJ9CiMgbGlzdCBzdHJ1Y3R1cmUKc3RyKGRhdGFfbmVzJHllYXJfMjAxOCwgbWF4LmxldmVsID0gMSwgZ2l2ZS5hdHRyID0gRiwgbm8ubGlzdCA9IFQpCmBgYAoKPiBBIGxpc3Qgb2YgYHIgbGVuZ3RoKGRhdGFfbmVzJHllYXJfMjAxOClgIGBkYXRhLmZyYW1lc2AsIG9uZSBmb3IgZWFjaCBzZWFsCgpGb3IgY29udmVuaWVuY2UsIHdlIGFnZ3JlZ2F0ZSBhbGwgYHIgbGVuZ3RoKGRhdGFfbmVzJHllYXJfMjAxOClgIGluZGl2aWR1YWxzIGludG8gb25lIGRhdGFzZXQuCgpgYGB7ciBkYXRhLWV4cGxvcmF0aW9uLTIwMTgtMywgZXZhbD1GQUxTRX0KIyBjb21iaW5lIGFsbCBpbmRpdmlkdWFscwpkYXRhXzIwMTggPC0gcmJpbmRsaXN0KGRhdGFfbmVzJHllYXJfMjAxOCkKCiMgZGlzcGxheQpEVDo6ZGF0YXRhYmxlKGRhdGFfMjAxOFtzYW1wbGUuaW50KC5OLCAxMCksIF0sIG9wdGlvbnMgPSBsaXN0KHNjcm9sbFggPSBUKSkKYGBgCmBgYHtyIGRhdGEtZXhwbG9yYXRpb24tMjAxOC00LCBlY2hvPUZBTFNFLCByZXN1bHRzPSdhc2lzJ30KIyBjb21iaW5lIGFsbCBpbmRpdmlkdWFscwpkYXRhXzIwMTggPC0gcmJpbmRsaXN0KGRhdGFfbmVzJHllYXJfMjAxOCkKCiMgdGl0bGUKY2F0KCI8dGFibGUgc3R5bGU9J3dpZHRoOiA1MCUnPiIsIAogICAgcGFzdGUwKAogICAgICAiPGNhcHRpb24+IiwgCiAgICAgICIoI3RhYjpteURUaHRtbHRvb2xzKSIsIAogICAgICAiU2FtcGxlIG9mIDEwIHJhbmRvbSByb3dzIGZyb20gYGRhdGFfMjAxOGAiLCAKICAgICAgIjwvY2FwdGlvbj4iKSwgCiAgICAiPC90YWJsZT4iLCAKICAgIHNlcCA9ICJcbiIpCgojIGRpc3BsYXkKRFQ6OmRhdGF0YWJsZShkYXRhXzIwMThbc2FtcGxlLmludCguTiwgMTApLCBdLCBvcHRpb25zID0gbGlzdChzY3JvbGxYID0gVCkpCmBgYAoKIyMgU3VtbWFyeQoKYGBge3IgZGF0YS1leHBsb3JhdGlvbi0yMDE4LTV9CiMgcmF3X2RhdGEKZGF0YV8yMDE4WywgLigKICBuYl9kYXlzX3JlY29yZGVkID0gdW5pcXVlTihhcy5EYXRlKGRhdGUpKSwKICBuYl9kaXZlcyA9IC5OLAogIG1heGRlcHRoX21lYW4gPSBtZWFuKG1heGRlcHRoKSwKICBkZHVyYXRpb25fbWVhbiA9IG1lYW4oZGR1cmF0aW9uKSwKICBib3R0dGltZV9tZWFuID0gbWVhbihib3R0dGltZSksCiAgcGRpX21lYW4gPSBtZWFuKHBkaSwgbmEucm0gPSBUKQopLCBieSA9IC5pZF0gJT4lCiAgc2FibGUoCiAgICBjYXB0aW9uID0gIlN1bW1hcnkgZGl2aW5nIGluZm9ybWF0aW9uIHJlbGF0aXZlIHRvIGVhY2ggMjAxOCBpbmRpdmlkdWFsIiwKICAgIGRpZ2l0cyA9IDIKICApCmBgYAo+IFZlcnkgbmljZSBkYXRhc2V0IDopCgojIyBTb21lIGV4cGxhbmF0b3J5IHBsb3RzCgojIyMgTWlzc2luZyB2YWx1ZXMKCmBgYHtyIGRhdGEtZXhwbG9yYXRpb24tMjAxOC02LCBmaWcuY2FwPSJDaGVjayBmb3IgbWlzc2luZyB2YWx1ZSBpbiAyMDE4LWluZGl2aWR1YWxzIiwgZmlnLndpZHRoPTl9CiMgYnVpbGQgZGF0YXNldCB0byBjaGVjayBmb3IgbWlzc2luZyB2YWx1ZXMKZGF0YVBsb3QgPC0gbWVsdChkYXRhXzIwMThbLCAuKC5pZCwgaXMubmEoLlNEKSksIC5TRGNvbCA9IC1jKAogICIuaWQiLAogICJkaXZlbnVtYmVyIiwKICAieWVhciIsCiAgIm1vbnRoIiwKICAiZGF5IiwKICAiaG91ciIsCiAgIm1pbiIsCiAgInNlYyIsCiAgImp1bGRhdGUiLAogICJkaXZldHlwZSIsCiAgImRhdGUiLAogICJwaGFzZSIsCiAgImxhdCIsCiAgImxvbiIKKV0pCiMgYWRkIHRoZSBpZCBvZiByb3dzCmRhdGFQbG90WywgaWRfcm93IDo9IGMoMTouTiksIGJ5ID0gYygidmFyaWFibGUiLCAiLmlkIildCgojIHBsb3QKZ2dwbG90KGRhdGFQbG90LCBhZXMoeCA9IHZhcmlhYmxlLCB5ID0gaWRfcm93LCBmaWxsID0gdmFsdWUpKSArCiAgZ2VvbV90aWxlKCkgKwogIGxhYnMoeCA9ICJBdHRyaWJ1dGVzIiwgeSA9ICJSb3dzIikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKAogICAgdmFsdWVzID0gYygid2hpdGUiLCAiYmxhY2siKSwKICAgIGxhYmVscyA9IGMoIlJlYWwiLCAiTWlzc2luZyIpCiAgKSArCiAgZmFjZXRfd3JhcCguaWQgfiAuLCBzY2FsZXMgPSAiZnJlZV95IikgKwogIHRoZW1lX2pqbygpICsKICB0aGVtZSgKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwKICAgIGxlZ2VuZC5rZXkgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImJsYWNrIikKICApCmBgYAoKU28gZmFyIHNvIGdvb2QsIG9ubHkgZmV3IHZhcmlhYmxlcyBzZWVtcyB0byBoYXZlIG1pc3NpbmcgdmFsdWVzOgogIApgYGB7ciBkYXRhLWV4cGxvcmF0aW9uLTIwMTgtN30KIyB0YWJsZSB3aXRoIHBlcmNlbnQKdGFibGVfaW50ZXIgPC0gZGF0YV8yMDE4WywgbGFwcGx5KC5TRCwgZnVuY3Rpb24oeCkgewogIHJvdW5kKGxlbmd0aCh4W2lzLm5hKHgpXSkgKiAxMDAgLyBsZW5ndGgoeCksIDEpCn0pLCAuU0Rjb2wgPSAtYygKICAiLmlkIiwKICAiZGl2ZW51bWJlciIsCiAgInllYXIiLAogICJtb250aCIsCiAgImRheSIsCiAgImhvdXIiLAogICJtaW4iLAogICJzZWMiLAogICJqdWxkYXRlIiwKICAiZGl2ZXR5cGUiLAogICJkYXRlIiwKICAicGhhc2UiLAogICJsYXQiLAogICJsb24iCildCgojIGZpbmQgd2hpY2ggYXJlIGRpZmZlcmVudCBmcm9tIDAKY29uZF9pbnRlciA8LSBzYXBwbHkodGFibGVfaW50ZXIsIGZ1bmN0aW9uKHgpIHsKICB4ID09IDAKfSkKCiMgZGlzcGxheSB0aGUgcGVyY2VudGFnZXMgdGhhdCBhcmUgb3ZlciAwCnRhYmxlX2ludGVyWywgd2hpY2goY29uZF9pbnRlcikgOj0gTlVMTF0gJT4lCiAgc2FibGUoY2FwdGlvbiA9ICJQZXJjZW50YWdlIG9mIG1pc3NpbmcgdmFsdWVzIHBlciBjb2x1bW5zIGhhdmluZyBtaXNzaW5nIHZhbHVlcyEiKSAlPiUKICBzY3JvbGxfYm94KHdpZHRoID0gIjEwMCUiKQpgYGAKCiMjIyBPdXRsaWVycyB7LnRhYnNldH0KCk9rLCBsZXQncyBoYXZlIGEgbG9vayBhdCBhbGwgdGhlIGRhdGEuIEJ1dCBmaXJzdCwgd2UgaGF2ZSB0byByZW1vdmUgb3V0bGllcnMuIFNvbWUgb2YgdGhlbSBhcmUgcXVpZXQgZWFzeSB0byBzcG90IGxvb2tpbmcgYXQgdGhlIGRpc3RyaWJ1dGlvbiBvZiBkaXZlIGR1cmF0aW9uOgoKIyMjIyBCZWZvcmUgey19CgpgYGB7ciBkYXRhLWV4cGxvcmF0aW9uLTIwMTgtOCwgZmlnLmNhcD0nRGlzdHJpYnV0aW9uIG9mIGBkZHVyYXRpb25gIGZvciBlYWNoIHNlYWwuIFRoZSBkYXNoZWQgbGluZSBoaWdobGlnaHQgdGhlICJzdWJqZWN0aXZlIiB0aHJlc2hvbGQgdXNlZCB0byByZW1vdmUgb3V0bGllcnMgKDMwMDAgc2VjKScsIGZpZy5oZWlnaHQ9M30KZ2dwbG90KAogIGRhdGFfMjAxOFssIC5TRF1bLCBzdGF0ZSA6PSAiQmVmb3JlIl0sCiAgYWVzKHggPSBkZHVyYXRpb24sIGZpbGwgPSAuaWQpCikgKwogIGdlb21faGlzdG9ncmFtKHNob3cubGVnZW5kID0gRkFMU0UpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAzMDAwLCBsaW5ldHlwZSA9ICJsb25nZGFzaCIpICsKICBmYWNldF9ncmlkKHN0YXRlIH4gLmlkLAogICAgICAgICAgICAgc2NhbGVzID0gImZyZWUiCiAgKSArCiAgbGFicyh5ID0gIiMgb2YgZGl2ZXMiLCB4ID0gIkRpdmUgZHVyYXRpb24gKHMpIikgKwogIHRoZW1lX2pqbygpCmBgYAoKIyMjIyBBZnRlciB7LX0KCmBgYHtyIGRhdGEtZXhwbG9yYXRpb24tMjAxOC05LCBmaWcuY2FwPSdTYW1lIGRpc3RyaWJ1dGlvbiBvZiBgZGR1cmF0aW9uYCBmb3IgZWFjaCBzZWFsIGJ1dCBhZnRlciByZW1vdmluZyBhbnkgYGRkdXJhdGlvbmAgPiAzMDAwIHNlYy4gVGhlIGRhc2hlZCBsaW5lIGhpZ2hsaWdodCB0aGUgInN1YmplY3RpdmUiIHRocmVzaG9sZCB1c2VkIHRvIHJlbW92ZSBvdXRsaWVycycsIGZpZy5oZWlnaHQ9M30KZ2dwbG90KAogIGRhdGFfMjAxOFtkZHVyYXRpb24gPCAzMDAwLCBdW11bLCBzdGF0ZSA6PSAiQWZ0ZXIiXSwKICBhZXMoeCA9IGRkdXJhdGlvbiwgZmlsbCA9IC5pZCkKKSArCiAgZ2VvbV9oaXN0b2dyYW0oc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDMwMDAsIGxpbmV0eXBlID0gImxvbmdkYXNoIikgKwogIGZhY2V0X2dyaWQoc3RhdGUgfiAuaWQsCiAgICAgICAgICAgICBzY2FsZXMgPSAiZnJlZSIKICApICsKICBsYWJzKHggPSAiIyBvZiBkaXZlcyIsIHkgPSAiRGl2ZSBkdXJhdGlvbiAocykiKSArCiAgdGhlbWVfampvKCkKYGBgCgpJdCBzZWVtcyBtdWNoIGJldHRlciwgc28gbGV0J3MgcmVtb3ZlIGFueSByb3dzIHdpdGggYGRkdXJhdGlvbmAgPiAzMDAwIHNlYy4KCmBgYHtyIGRhdGEtZXhwbG9yYXRpb24tMjAxOC0xMH0KIyBmaWx0ZXIgZGF0YQpkYXRhXzIwMThfZmlsdGVyIDwtIGRhdGFfMjAxOFtkZHVyYXRpb24gPCAzMDAwLCBdCgojIG5icm93IHJlbW92ZWQKZGF0YV8yMDE4W2RkdXJhdGlvbiA+PSAzMDAwLCAuKG5iX3Jvd19yZW1vdmVkID0gLk4pLCBieSA9IC5pZF0gJT4lCiAgc2FibGUoY2FwdGlvbiA9ICIjIG9mIHJvd3MgcmVtb3ZlZCBieSAyMDE4LWluZGl2aWR1YWxzIikKYGBgCgojIyMgQ2hlY2sgZGF5IGFuZCBuaWdodCB7LnRhYnNldH0KCiMjIyMgTGlnaHQgbGV2ZWxzCgpgYGB7ciBkYXRhLWV4cGxvcmF0aW9uLTIwMTgtMTEsIGZpZy5jYXA9IlZpc3VhbGl6YXRpb24gb2YgbGlnaHQgbGV2ZWwgYXQgdGhlIHN1cmZhY2UgYWxvbmcgMjAxOC1pbmRpdmlkdWFscycgdHJpcCIsIGZpZy5oZWlnaHQ9Nn0KIyBsZXQncyBmaXJzdCBhdmVyYWdlIGBsaWdodGF0c3VyZmAgYnkgaW5kaXZpZHVhbHMsIGRheSBzaW5jZSBkZXBhcnR1cmUgYW5kIGhvdXIKZGF0YVBsb3QgPC0gZGF0YV8yMDE4WywgLihsaWdodGF0c3VyZiA9IG1lZGlhbihsaWdodGF0c3VyZikpLAogICAgICAgICAgICAgICAgICAgICAgYnkgPSAuKC5pZCwgZGF5X2RlcGFydHVyZSwgZGF0ZSA9IGFzLkRhdGUoZGF0ZSksIGhvdXIpCl0KCiMgZGlzcGxheSB0aGUgcmVzdWx0CmdncGxvdChkYXRhUGxvdCwgYWVzKHggPSBkYXlfZGVwYXJ0dXJlLCB5ID0gaG91ciwgZmlsbCA9IGxpZ2h0YXRzdXJmKSkgKwogIGdlb21fdGlsZSgpICsKICBmYWNldF9ncmlkKC5pZCB+IC4pICsKICB0aGVtZV9qam8oKSArCiAgbGFicyh4ID0gIiMgb2YgZGF5cyBzaW5jZSBkZXBhcnR1cmUiLCAKICAgICAgIHkgPSAiSG91ciIsIAogICAgICAgZmlsbCA9ICJMaWdodCBsZXZlbCBhdCB0aGUgc3VyZmFjZSIpKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoImJvdHRvbSIpKQpgYGAKCiMjIyMgRGF5IGFuZCBuaWdodCBkZXRlY3Rpb24KCmBgYHtyIGRhdGEtZXhwbG9yYXRpb24tMjAxOC0xMiwgZmlnLmNhcD0iVmlzdWFsaXphdGlvbiBvZiBkZXRlY3RlZCBuaWdodCB0aW1lIGFuZCBkYXkgdGltZSBhbG9uZyAyMDE4LWluZGl2aWR1YWxzJyB0cmlwIiwgZmlnLmhlaWdodD02fQojIGxldCdzIGZpcnN0IGF2ZXJhZ2UgYGxpZ2h0YXRzdXJmYCBieSBpbmRpdmlkdWFscywgZGF5IHNpbmNlIGRlcGFydHVyZSBhbmQgaG91cgpkYXRhUGxvdCA8LSBkYXRhXzIwMThbLCAuKGxpZ2h0YXRzdXJmID0gbWVkaWFuKGxpZ2h0YXRzdXJmKSksCiAgICAgICAgICAgICAgICAgICAgICBieSA9IC4oLmlkLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlfZGVwYXJ0dXJlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRlID0gYXMuRGF0ZShkYXRlKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaG91ciwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGhhc2UpCl0KCiMgZGlzcGxheSB0aGUgcmVzdWx0CmdncGxvdChkYXRhUGxvdCwgYWVzKHggPSBkYXlfZGVwYXJ0dXJlLCB5ID0gaG91ciwgZmlsbCA9IHBoYXNlKSkgKwogIGdlb21fdGlsZSgpICsKICBmYWNldF9ncmlkKC5pZCB+IC4pICsKICB0aGVtZV9qam8oKSArCiAgbGFicyh4ID0gIiMgb2YgZGF5cyBzaW5jZSBkZXBhcnR1cmUiLCAKICAgICAgIHkgPSAiSG91ciIsIAogICAgICAgZmlsbCA9ICJEYXkgdGltZSBhbmQgbmlnaHQgdGltZSBhcyBkZXRlY3RlZCBieSB0aGUgYGNhbF9waGFzZV9kYXlgIGZ1bmN0aW9uIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoImJvdHRvbSIpKQpgYGAKCiMjIyBBbGwgVmFyaWFibGVzIAoKYGBge3IgZGF0YS1leHBsb3JhdGlvbi0yMDE4LTEzfQpuYW1lc19kaXNwbGF5IDwtIG5hbWVzKGRhdGFfMjAxOF9maWx0ZXJbLCAtYygKICAiLmlkIiwKICAiZGF0ZSIsCiAgImRpdmVudW1iZXIiLAogICJ5ZWFyIiwKICAibW9udGgiLAogICJkYXkiLAogICJob3VyIiwKICAibWluIiwKICAic2VjIiwKICAianVsZGF0ZSIsCiAgImRpdmV0eXBlIiwKICAiZXVwaG90aWNkZXB0aCIsCiAgInRoZXJtb2NsaW5lZGVwdGgiLAogICJkYXlfZGVwYXJ0dXJlIiwKICAicGhhc2UiLAogICJsYXQiLAogICJsb24iLAogICJkaXN0X2RlcCIKKV0pCmBgYAoKYGBge3IgZGF0YS1leHBsb3JhdGlvbi0yMDE4LTE0LCBldmFsPUZBTFNFLCBpbmNsdWRlPVRSVUV9CmZvciAoaSBpbiBuYW1lc19kaXNwbGF5KSB7CiAgY2F0KCIjIyMjIyIsIGksICJ7LnVubGlzdGVkIC51bm51bWJlcmVkfSBcbiIpCiAgaWYgKGkgPT0gIm1heGRlcHRoIikgewogICAgcHJpbnQoCiAgICAgIGdncGxvdCgpICsKICAgICAgICBnZW9tX3BvaW50KAogICAgICAgICAgZGF0YSA9IGRhdGFfMjAxOF9maWx0ZXJbLCAuKAogICAgICAgICAgICAuaWQsCiAgICAgICAgICAgIGRhdGUsCiAgICAgICAgICAgIHRoZXJtb2NsaW5lZGVwdGgKICAgICAgICAgICldLAogICAgICAgICAgYWVzKAogICAgICAgICAgICB4ID0gYXMuRGF0ZShkYXRlKSwKICAgICAgICAgICAgeSA9IC10aGVybW9jbGluZWRlcHRoLAogICAgICAgICAgICBjb2xvdXIgPSAiVGhlcm1vY2xpbmUgKG0pIgogICAgICAgICAgKSwKICAgICAgICAgIGFscGhhID0gLjIsCiAgICAgICAgICBzaXplID0gLjUKICAgICAgICApICsKICAgICAgICBnZW9tX3BvaW50KAogICAgICAgICAgZGF0YSA9IGRhdGFfMjAxOF9maWx0ZXJbLCAuKAogICAgICAgICAgICAuaWQsCiAgICAgICAgICAgIGRhdGUsCiAgICAgICAgICAgIGV1cGhvdGljZGVwdGgKICAgICAgICAgICldLAogICAgICAgICAgYWVzKAogICAgICAgICAgICB4ID0gYXMuRGF0ZShkYXRlKSwKICAgICAgICAgICAgeSA9IC1ldXBob3RpY2RlcHRoLAogICAgICAgICAgICBjb2xvdXIgPSAiRXVwaG90aWMgKG0pIgogICAgICAgICAgKSwKICAgICAgICAgIGFscGhhID0gLjIsCiAgICAgICAgICBzaXplID0gLjUKICAgICAgICApICsKICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKAogICAgICAgICAgdmFsdWVzID0gYygKICAgICAgICAgICAgIlRoZXJtb2NsaW5lIChtKSIgPSAicmVkIiwKICAgICAgICAgICAgIkV1cGhvdGljIChtKSIgPSAiYmxhY2siCiAgICAgICAgICApLAogICAgICAgICAgbmFtZSA9ICJab25lIgogICAgICAgICkgKwogICAgICAgIG5ld19zY2FsZV9jb2xvcigpICsKICAgICAgICBnZW9tX3BvaW50KAogICAgICAgICAgZGF0YSA9IG1lbHQoZGF0YV8yMDE4X2ZpbHRlclssIC4oLmlkLCBkYXRlLCBnZXQoaSkpXSwgCiAgICAgICAgICAgICAgICAgICAgICBpZC52YXJzID0gYygiLmlkIiwgImRhdGUiKSksCiAgICAgICAgICBhZXMoCiAgICAgICAgICAgIHggPSBhcy5EYXRlKGRhdGUpLAogICAgICAgICAgICB5ID0gLXZhbHVlLAogICAgICAgICAgICBjb2wgPSAuaWQKICAgICAgICAgICksCiAgICAgICAgICBhbHBoYSA9IDEgLyAxMCwKICAgICAgICAgIHNpemUgPSAuNSwKICAgICAgICAgIHNob3cubGVnZW5kID0gRkFMU0UKICAgICAgICApICsKICAgICAgICBmYWNldF93cmFwKC4gfiAuaWQsIHNjYWxlcyA9ICJmcmVlIikgKwogICAgICAgIHNjYWxlX3hfZGF0ZShkYXRlX2xhYmVscyA9ICIlbS8lWSIpICsKICAgICAgICBsYWJzKHggPSAiRGF0ZSIsIHkgPSAiTWF4aW11bSBEZXB0aCAobSkiKSArCiAgICAgICAgdGhlbWVfampvKCkgKwogICAgICAgIHRoZW1lKAogICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwKICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iCiAgICAgICAgKQogICAgKQogICAgY2F0KCI8YmxvY2txdW90ZT4gQ29uc2lkZXJpbmcgYGluZF8yMDE4MDc0YCBoYXMgc2xpZ2h0bHkgZGlmZmVyZW50IHZhbHVlcyB0aGFuIG90aGVyIGluZGl2aWR1YWxzIGZvciB0aGUgdGhlcm1vY2xpbmUgZGVwdGgsIGl0IHdvdWxkIGJlIGludGVyZXN0aW5nIHRvIHNlZSB3aGVyZSB0aGUgYW5pbWFsIHdlbnQuIDwvYmxvY2txdW90ZT4iKQogIH0gZWxzZSBpZiAoaSA9PSAiZHJpZnRyYXRlIikgewogICAgcHJpbnQoCiAgICAgIGdncGxvdCgKICAgICAgICBkYXRhID0gbWVsdChkYXRhXzIwMThfZmlsdGVyWywgLiguaWQsIGRhdGUsIGdldChpKSwgZGl2ZXR5cGUpXSwgCiAgICAgICAgICAgICAgICAgICAgaWQudmFycyA9IGMoIi5pZCIsICJkYXRlIiwgImRpdmV0eXBlIikpLAogICAgICAgIGFlcygKICAgICAgICAgIHggPSBhcy5EYXRlKGRhdGUpLAogICAgICAgICAgeSA9IHZhbHVlLAogICAgICAgICAgY29sID0gZGl2ZXR5cGUKICAgICAgICApCiAgICAgICkgKwogICAgICAgIGdlb21fcG9pbnQoCiAgICAgICAgICBhbHBoYSA9IDEgLyAxMCwKICAgICAgICAgIHNpemUgPSAuNQogICAgICAgICkgKwogICAgICAgIGZhY2V0X3dyYXAoLiB+IC5pZCwgc2NhbGVzID0gImZyZWUiKSArCiAgICAgICAgc2NhbGVfeF9kYXRlKGRhdGVfbGFiZWxzID0gIiVtLyVZIikgKwogICAgICAgIGxhYnMoeCA9ICJEYXRlIiwgeSA9ICJEcmlmdCBSYXRlICdtL3MiLCBjb2wgPSAiRGl2ZSBUeXBlIikgKwogICAgICAgIHRoZW1lX2pqbygpICsKICAgICAgICB0aGVtZSgKICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksCiAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIgogICAgICAgICkgKwogICAgICAgIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdCgKICAgICAgICAgIHNpemUgPSA3LAogICAgICAgICAgYWxwaGEgPSAxCiAgICAgICAgKSkpCiAgICApCiAgfSBlbHNlIHsKICAgIHByaW50KAogICAgICBnZ3Bsb3QoCiAgICAgICAgZGF0YSA9IG1lbHQoZGF0YV8yMDE4X2ZpbHRlclssIC4oLmlkLCBkYXRlLCBnZXQoaSkpXSwgCiAgICAgICAgICAgICAgICAgICAgaWQudmFycyA9IGMoIi5pZCIsICJkYXRlIikpLAogICAgICAgIGFlcygKICAgICAgICAgIHggPSBhcy5EYXRlKGRhdGUpLAogICAgICAgICAgeSA9IHZhbHVlLAogICAgICAgICAgY29sID0gLmlkCiAgICAgICAgKQogICAgICApICsKICAgICAgICBnZW9tX3BvaW50KAogICAgICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRSwKICAgICAgICAgIGFscGhhID0gMSAvIDEwLAogICAgICAgICAgc2l6ZSA9IC41CiAgICAgICAgKSArCiAgICAgICAgZmFjZXRfd3JhcCguIH4gLmlkLCBzY2FsZXMgPSAiZnJlZSIpICsKICAgICAgICBzY2FsZV94X2RhdGUoZGF0ZV9sYWJlbHMgPSAiJW0vJVkiKSArCiAgICAgICAgbGFicyh4ID0gIkRhdGUiLCB5ID0gaSkgKwogICAgICAgIHRoZW1lX2pqbygpICsKICAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQogICAgKQogIH0KICAKICBjYXQoIlxuIFxuIikKfQpgYGAKCiMjIyB7LnVubGlzdGVkIC51bm51bWJlcmVkIC50YWJzZXQgLnRhYnNldC1mYWRlIC50YWJzZXQtcGlsbHN9CgpgYGB7ciBkYXRhLWV4cGxvcmF0aW9uLTIwMTgtMTUsIHJlc3VsdHM9J2FzaXMnLCBjYWNoZT1UUlVFLCBlY2hvPUZBTFNFfQpmb3IgKGkgaW4gbmFtZXNfZGlzcGxheSkgewogIGNhdCgiIyMjIyIsIGksICJ7LnVubGlzdGVkIC51bm51bWJlcmVkfSBcbiIpCiAgaWYgKGkgPT0gIm1heGRlcHRoIikgewogICAgcHJpbnQoCiAgICAgIGdncGxvdCgpICsKICAgICAgICBnZW9tX3BvaW50KAogICAgICAgICAgZGF0YSA9IGRhdGFfMjAxOF9maWx0ZXJbLCAuKAogICAgICAgICAgICAuaWQsCiAgICAgICAgICAgIGRhdGUsCiAgICAgICAgICAgIHRoZXJtb2NsaW5lZGVwdGgKICAgICAgICAgICldLAogICAgICAgICAgYWVzKAogICAgICAgICAgICB4ID0gYXMuRGF0ZShkYXRlKSwKICAgICAgICAgICAgeSA9IC10aGVybW9jbGluZWRlcHRoLAogICAgICAgICAgICBjb2xvdXIgPSAiVGhlcm1vY2xpbmUgKG0pIgogICAgICAgICAgKSwKICAgICAgICAgIGFscGhhID0gLjIsCiAgICAgICAgICBzaXplID0gLjUKICAgICAgICApICsKICAgICAgICBnZW9tX3BvaW50KAogICAgICAgICAgZGF0YSA9IGRhdGFfMjAxOF9maWx0ZXJbLCAuKAogICAgICAgICAgICAuaWQsCiAgICAgICAgICAgIGRhdGUsCiAgICAgICAgICAgIGV1cGhvdGljZGVwdGgKICAgICAgICAgICldLAogICAgICAgICAgYWVzKAogICAgICAgICAgICB4ID0gYXMuRGF0ZShkYXRlKSwKICAgICAgICAgICAgeSA9IC1ldXBob3RpY2RlcHRoLAogICAgICAgICAgICBjb2xvdXIgPSAiRXVwaG90aWMgKG0pIgogICAgICAgICAgKSwKICAgICAgICAgIGFscGhhID0gLjIsCiAgICAgICAgICBzaXplID0gLjUKICAgICAgICApICsKICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKAogICAgICAgICAgdmFsdWVzID0gYygKICAgICAgICAgICAgIlRoZXJtb2NsaW5lIChtKSIgPSAicmVkIiwKICAgICAgICAgICAgIkV1cGhvdGljIChtKSIgPSAiYmxhY2siCiAgICAgICAgICApLAogICAgICAgICAgbmFtZSA9ICJab25lIgogICAgICAgICkgKwogICAgICAgIG5ld19zY2FsZV9jb2xvcigpICsKICAgICAgICBnZW9tX3BvaW50KAogICAgICAgICAgZGF0YSA9IG1lbHQoZGF0YV8yMDE4X2ZpbHRlclssIC4oLmlkLCBkYXRlLCBnZXQoaSkpXSwgCiAgICAgICAgICAgICAgICAgICAgICBpZC52YXJzID0gYygiLmlkIiwgImRhdGUiKSksCiAgICAgICAgICBhZXMoCiAgICAgICAgICAgIHggPSBhcy5EYXRlKGRhdGUpLAogICAgICAgICAgICB5ID0gLXZhbHVlLAogICAgICAgICAgICBjb2wgPSAuaWQKICAgICAgICAgICksCiAgICAgICAgICBhbHBoYSA9IDEgLyAxMCwKICAgICAgICAgIHNpemUgPSAuNSwKICAgICAgICAgIHNob3cubGVnZW5kID0gRkFMU0UKICAgICAgICApICsKICAgICAgICBmYWNldF93cmFwKC4gfiAuaWQsIHNjYWxlcyA9ICJmcmVlIikgKwogICAgICAgIHNjYWxlX3hfZGF0ZShkYXRlX2xhYmVscyA9ICIlbS8lWSIpICsKICAgICAgICBsYWJzKHggPSAiRGF0ZSIsIHkgPSAiTWF4aW11bSBEZXB0aCAobSkiKSArCiAgICAgICAgdGhlbWVfampvKCkgKwogICAgICAgIHRoZW1lKAogICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwKICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iCiAgICAgICAgKQogICAgKQogICAgY2F0KCI8YmxvY2txdW90ZT4gQ29uc2lkZXJpbmcgYGluZF8yMDE4MDc0YCBoYXMgc2xpZ2h0bHkgZGlmZmVyZW50IHZhbHVlcyB0aGFuIG90aGVyIGluZGl2aWR1YWxzIGZvciB0aGUgdGhlcm1vY2xpbmUgZGVwdGgsIGl0IHdvdWxkIGJlIGludGVyZXN0aW5nIHRvIHNlZSB3aGVyZSB0aGUgYW5pbWFsIHdlbnQuIDwvYmxvY2txdW90ZT4iKQogIH0gZWxzZSBpZiAoaSA9PSAiZHJpZnRyYXRlIikgewogICAgcHJpbnQoCiAgICAgIGdncGxvdCgKICAgICAgICBkYXRhID0gbWVsdChkYXRhXzIwMThfZmlsdGVyWywgLiguaWQsIGRhdGUsIGdldChpKSwgZGl2ZXR5cGUpXSwgCiAgICAgICAgICAgICAgICAgICAgaWQudmFycyA9IGMoIi5pZCIsICJkYXRlIiwgImRpdmV0eXBlIikpLAogICAgICAgIGFlcygKICAgICAgICAgIHggPSBhcy5EYXRlKGRhdGUpLAogICAgICAgICAgeSA9IHZhbHVlLAogICAgICAgICAgY29sID0gZGl2ZXR5cGUKICAgICAgICApCiAgICAgICkgKwogICAgICAgIGdlb21fcG9pbnQoCiAgICAgICAgICBhbHBoYSA9IDEgLyAxMCwKICAgICAgICAgIHNpemUgPSAuNQogICAgICAgICkgKwogICAgICAgIGZhY2V0X3dyYXAoLiB+IC5pZCwgc2NhbGVzID0gImZyZWUiKSArCiAgICAgICAgc2NhbGVfeF9kYXRlKGRhdGVfbGFiZWxzID0gIiVtLyVZIikgKwogICAgICAgIGxhYnMoeCA9ICJEYXRlIiwgeSA9ICJEcmlmdCBSYXRlICdtL3MiLCBjb2wgPSAiRGl2ZSBUeXBlIikgKwogICAgICAgIHRoZW1lX2pqbygpICsKICAgICAgICB0aGVtZSgKICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksCiAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIgogICAgICAgICkgKwogICAgICAgIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdCgKICAgICAgICAgIHNpemUgPSA3LAogICAgICAgICAgYWxwaGEgPSAxCiAgICAgICAgKSkpCiAgICApCiAgfSBlbHNlIHsKICAgIHByaW50KAogICAgICBnZ3Bsb3QoCiAgICAgICAgZGF0YSA9IG1lbHQoZGF0YV8yMDE4X2ZpbHRlclssIC4oLmlkLCBkYXRlLCBnZXQoaSkpXSwgCiAgICAgICAgICAgICAgICAgICAgaWQudmFycyA9IGMoIi5pZCIsICJkYXRlIikpLAogICAgICAgIGFlcygKICAgICAgICAgIHggPSBhcy5EYXRlKGRhdGUpLAogICAgICAgICAgeSA9IHZhbHVlLAogICAgICAgICAgY29sID0gLmlkCiAgICAgICAgKQogICAgICApICsKICAgICAgICBnZW9tX3BvaW50KAogICAgICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRSwKICAgICAgICAgIGFscGhhID0gMSAvIDEwLAogICAgICAgICAgc2l6ZSA9IC41CiAgICAgICAgKSArCiAgICAgICAgZmFjZXRfd3JhcCguIH4gLmlkLCBzY2FsZXMgPSAiZnJlZSIpICsKICAgICAgICBzY2FsZV94X2RhdGUoZGF0ZV9sYWJlbHMgPSAiJW0vJVkiKSArCiAgICAgICAgbGFicyh4ID0gIkRhdGUiLCB5ID0gaSkgKwogICAgICAgIHRoZW1lX2pqbygpICsKICAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQogICAgKQogIH0KICAKICBjYXQoIlxuIFxuIikKfQpgYGAKCiMjIyB7LnVubGlzdGVkIC51bm51bWJlcmVkfQoKPiBGZXcgcXVlc3Rpb25zLCB0aGF0IEkgc2hvdWxkIGxvb2sgaW50byBpdDoKICA+CiAgPiAqIGlzIHRoZSBiaW1vZGFsIGRpc3RyaWJ1dGlvbiBvZiBgZGR1cmF0aW9uYCwgYGRlc2N0aW1lYCBkdWUgdG8gbnljdGhlbWVyYWwgbWlncmF0aW9uPwogID4gKiBpcyB0aGUgYmltb2RhbCBkaXN0cmlidXRpb24gb2YgYGRlc2NyYXRlYCAoZXNwZWNpYWxseSBmb3IgYGluZDIwMTgwNzBgIGFuZCBgaW5kXzIwMTgwNzJgKSBkdWUgdG8gZHJpZnQgZGl2ZT8KICA+ICogaXMgYGxpZ2h0YXRib3R0YCBjb3VsZCBiZSB1c2VkIHRvIGlkZW50aWZ5IGJpb2x1bWluZXNjZW5jZSwgY2F1c2UgaXQgc2VlbXMgdGhlcmUgaXMgYSBsb3QgZ29pbmcgb24gYXQgdGhlIGJvdHRvbT8KICA+ICogYXJlIHRoZSB2YXJpYXRpb25zIG9ic2VydmVkIGZvciBgbGlnaHRhdHN1cmZgIGlzIGR1ZSB0byBtb29uIGN5Y2xlPwogID4gKiBub3Qgc3VyZSB3aHkgaXMgdGhlcmUgYSBiaW1vZGFsIGRpc3RyaWJ1dGlvbiBvZiBgdGVtcGF0Ym90dGAhCiAgPiAqIGBkcmlmcmF0ZWAgdGhhdCBvbmUgaXMgYXdlc29tZSEgVGhhbmtzIHRvIGBkaXZldHlwZWAgd2UgY2FuIGNsZWFybHkgc2VlIGEgcGF0dGVybiBvZiBob3cgZHJpZnRyYXRlIChhbmQgc28gYnVveWFuY3kpIGNoYW5nZSBhY2NvcmRpbmcgdGltZS4KPiAqIHRoZSBiaW1vZGFsIGRpc3RyaWJ1dGlvbiBvZiBgdmVydGljYWxzcGVlZDkwYCBhbmQgYHZlcnRpY2Fsc3BlZWQ5NWAgc2hvdWxkIGJlIGR1ZSB0byBkcmlmdCBkaXZlLgoKYGBge3IgZGF0YS1leHBsb3JhdGlvbi0yMDE4LTE2LCBldmFsPUZBTFNFLCBpbmNsdWRlPVRSVUV9CiMgc2FtZSBwbG90IHdpdGggYSBjb2xvcmVkIGZvciB0aGUgcGhhc2Ugb2YgdGhlIGRheQpmb3IgKGkgaW4gbmFtZXNfZGlzcGxheSkgewogIGNhdCgiIyMjIyIsIGksICJ7LX0gXG4iKQogIHByaW50KAogICAgZ2dwbG90KAogICAgICBkYXRhID0gbWVsdChkYXRhXzIwMThfZmlsdGVyWywgLiguaWQsIGRhdGUsIGdldChpKSwgcGhhc2UpXSwKICAgICAgICAgICAgICAgICAgaWQudmFycyA9IGMoCiAgICAgICAgICAgICAgICAgICAgIi5pZCIsCiAgICAgICAgICAgICAgICAgICAgImRhdGUiLAogICAgICAgICAgICAgICAgICAgICJwaGFzZSIKICAgICAgICAgICAgICAgICAgKQogICAgICApLAogICAgICBhZXMoCiAgICAgICAgeCA9IGFzLkRhdGUoZGF0ZSksCiAgICAgICAgeSA9IHZhbHVlLAogICAgICAgIGNvbCA9IHBoYXNlCiAgICAgICkKICAgICkgKwogICAgICBnZW9tX3BvaW50KAogICAgICAgIGFscGhhID0gMSAvIDEwLAogICAgICAgIHNpemUgPSAuNQogICAgICApICsKICAgICAgZmFjZXRfd3JhcCguIH4gLmlkLCBzY2FsZXMgPSAiZnJlZSIpICsKICAgICAgc2NhbGVfeF9kYXRlKGRhdGVfbGFiZWxzID0gIiVtLyVZIikgKwogICAgICBsYWJzKHggPSAiRGF0ZSIsIHkgPSBpKSArCiAgICAgIHRoZW1lX2pqbygpICsKICAgICAgdGhlbWUoCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIgogICAgICApICsKICAgICAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KAogICAgICAgIHNpemUgPSA3LAogICAgICAgIGFscGhhID0gMQogICAgICApKSkKICApCiAgY2F0KCJcbiBcbiIpCn0KYGBgCgojIyMgey51bmxpc3RlZCAudW5udW1iZXJlZCAudGFic2V0IC50YWJzZXQtZmFkZSAudGFic2V0LXBpbGxzfQoKYGBge3IgZGF0YS1leHBsb3JhdGlvbi0yMDE4LTE3LCByZXN1bHRzPSdhc2lzJywgY2FjaGU9VFJVRSwgZWNobz1GQUxTRX0KIyBzYW1lIHBsb3Qgd2l0aCBhIGNvbG9yZWQgZm9yIHRoZSBwaGFzZSBvZiB0aGUgZGF5CmZvciAoaSBpbiBuYW1lc19kaXNwbGF5KSB7CiAgY2F0KCIjIyMjIiwgaSwgInstfSBcbiIpCiAgcHJpbnQoCiAgICBnZ3Bsb3QoCiAgICAgIGRhdGEgPSBtZWx0KGRhdGFfMjAxOF9maWx0ZXJbLCAuKC5pZCwgZGF0ZSwgZ2V0KGkpLCBwaGFzZSldLAogICAgICAgICAgICAgICAgICBpZC52YXJzID0gYygKICAgICAgICAgICAgICAgICAgICAiLmlkIiwKICAgICAgICAgICAgICAgICAgICAiZGF0ZSIsCiAgICAgICAgICAgICAgICAgICAgInBoYXNlIgogICAgICAgICAgICAgICAgICApCiAgICAgICksCiAgICAgIGFlcygKICAgICAgICB4ID0gYXMuRGF0ZShkYXRlKSwKICAgICAgICB5ID0gdmFsdWUsCiAgICAgICAgY29sID0gcGhhc2UKICAgICAgKQogICAgKSArCiAgICAgIGdlb21fcG9pbnQoCiAgICAgICAgYWxwaGEgPSAxIC8gMTAsCiAgICAgICAgc2l6ZSA9IC41CiAgICAgICkgKwogICAgICBmYWNldF93cmFwKC4gfiAuaWQsIHNjYWxlcyA9ICJmcmVlIikgKwogICAgICBzY2FsZV94X2RhdGUoZGF0ZV9sYWJlbHMgPSAiJW0vJVkiKSArCiAgICAgIGxhYnMoeCA9ICJEYXRlIiwgeSA9IGkpICsKICAgICAgdGhlbWVfampvKCkgKwogICAgICB0aGVtZSgKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iCiAgICAgICkgKwogICAgICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3QoCiAgICAgICAgc2l6ZSA9IDcsCiAgICAgICAgYWxwaGEgPSAxCiAgICAgICkpKQogICkKICBjYXQoIlxuIFxuIikKfQpgYGAKCiMjIEFsbCBWYXJpYWJsZXMgZHVyaW5nIHRoZSBmaXJzdCBtb250aAoKYGBge3IgZGF0YS1leHBsb3JhdGlvbi0yMDE4LTE4LCBldmFsPUZBTFNFLCBpbmNsdWRlPVRSVUV9CmZvciAoaSBpbiBuYW1lc19kaXNwbGF5KSB7CiAgY2F0KCIjIyMjIiwgaSwgInsudW5saXN0ZWQgLnVubnVtYmVyZWR9IFxuIikKICBpZiAoaSA9PSAibWF4ZGVwdGgiKSB7CiAgICBwcmludCgKICAgICAgZ2dwbG90KCkgKwogICAgICAgIGdlb21fcG9pbnQoCiAgICAgICAgICBkYXRhID0gZGF0YV8yMDE4X2ZpbHRlcltkYXlfZGVwYXJ0dXJlIDwgMzIsIC4oCiAgICAgICAgICAgIC5pZCwKICAgICAgICAgICAgZGF5X2RlcGFydHVyZSwKICAgICAgICAgICAgdGhlcm1vY2xpbmVkZXB0aAogICAgICAgICAgKV0sCiAgICAgICAgICBhZXMoCiAgICAgICAgICAgIHggPSBkYXlfZGVwYXJ0dXJlLAogICAgICAgICAgICB5ID0gLXRoZXJtb2NsaW5lZGVwdGgsCiAgICAgICAgICAgIGNvbG91ciA9ICJUaGVybW9jbGluZSAobSkiLAogICAgICAgICAgICBncm91cCA9IGRheV9kZXBhcnR1cmUKICAgICAgICAgICksCiAgICAgICAgICBhbHBoYSA9IC4yLAogICAgICAgICAgc2l6ZSA9IC41CiAgICAgICAgKSArCiAgICAgICAgZ2VvbV9wb2ludCgKICAgICAgICAgIGRhdGEgPSBkYXRhXzIwMThfZmlsdGVyW2RheV9kZXBhcnR1cmUgPCAzMiwgLigKICAgICAgICAgICAgLmlkLAogICAgICAgICAgICBkYXlfZGVwYXJ0dXJlLAogICAgICAgICAgICBldXBob3RpY2RlcHRoCiAgICAgICAgICApXSwKICAgICAgICAgIGFlcygKICAgICAgICAgICAgeCA9IGRheV9kZXBhcnR1cmUsCiAgICAgICAgICAgIHkgPSAtZXVwaG90aWNkZXB0aCwKICAgICAgICAgICAgY29sb3VyID0gIkV1cGhvdGljIChtKSIsCiAgICAgICAgICAgIGdyb3VwID0gZGF5X2RlcGFydHVyZQogICAgICAgICAgKSwKICAgICAgICAgIGFscGhhID0gLjIsCiAgICAgICAgICBzaXplID0gLjUKICAgICAgICApICsKICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKAogICAgICAgICAgdmFsdWVzID0gYygKICAgICAgICAgICAgIlRoZXJtb2NsaW5lIChtKSIgPSAicmVkIiwKICAgICAgICAgICAgIkV1cGhvdGljIChtKSIgPSAiYmxhY2siCiAgICAgICAgICApLAogICAgICAgICAgbmFtZSA9ICJab25lIgogICAgICAgICkgKwogICAgICAgIG5ld19zY2FsZV9jb2xvcigpICsKICAgICAgICBnZW9tX2JveHBsb3QoCiAgICAgICAgICBkYXRhID0gbWVsdChkYXRhXzIwMThfZmlsdGVyW2RheV9kZXBhcnR1cmUgPCAzMiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4oLmlkLCBkYXlfZGVwYXJ0dXJlLCBnZXQoaSkpXSwgCiAgICAgICAgICAgICAgICAgICAgICBpZC52YXJzID0gYygiLmlkIiwgImRheV9kZXBhcnR1cmUiKSksCiAgICAgICAgICBhZXMoCiAgICAgICAgICAgIHggPSBkYXlfZGVwYXJ0dXJlLAogICAgICAgICAgICB5ID0gLXZhbHVlLAogICAgICAgICAgICBjb2wgPSAuaWQsCiAgICAgICAgICAgIGdyb3VwID0gZGF5X2RlcGFydHVyZQogICAgICAgICAgKSwKICAgICAgICAgIGFscGhhID0gMSAvIDEwLAogICAgICAgICAgc2l6ZSA9IC41LAogICAgICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRQogICAgICAgICkgKwogICAgICAgIGZhY2V0X3dyYXAoLiB+IC5pZCwgc2NhbGVzID0gImZyZWUiKSArCiAgICAgICAgbGFicyh4ID0gIiMgZGF5cyBzaW5jZSBkZXBhcnR1cmUiLCB5ID0gIk1heGltdW0gRGVwdGggKG0pIikgKwogICAgICAgIHRoZW1lX2pqbygpICsKICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKICAgICkKICB9IGVsc2UgewogICAgcHJpbnQoCiAgICAgIGdncGxvdCgKICAgICAgICBkYXRhID0gbWVsdChkYXRhXzIwMThfZmlsdGVyW2RheV9kZXBhcnR1cmUgPCAzMiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuKC5pZCwgZGF5X2RlcGFydHVyZSwgZ2V0KGkpKV0sIAogICAgICAgICAgICAgICAgICAgIGlkLnZhcnMgPSBjKCIuaWQiLCAiZGF5X2RlcGFydHVyZSIpKSwKICAgICAgICBhZXMoCiAgICAgICAgICB4ID0gZGF5X2RlcGFydHVyZSwKICAgICAgICAgIHkgPSB2YWx1ZSwKICAgICAgICAgIGNvbG9yID0gLmlkLAogICAgICAgICAgZ3JvdXAgPSBkYXlfZGVwYXJ0dXJlCiAgICAgICAgKQogICAgICApICsKICAgICAgICBnZW9tX2JveHBsb3QoCiAgICAgICAgICBzaG93LmxlZ2VuZCA9IEZBTFNFLAogICAgICAgICAgYWxwaGEgPSAxIC8gMTAsCiAgICAgICAgICBzaXplID0gLjUKICAgICAgICApICsKICAgICAgICBmYWNldF93cmFwKC4gfiAuaWQsIHNjYWxlcyA9ICJmcmVlIikgKwogICAgICAgIGxhYnMoeCA9ICIjIGRheXMgc2luY2UgZGVwYXJ0dXJlIiwgeSA9IGkpICsKICAgICAgICB0aGVtZV9qam8oKQogICAgKQogIH0KICBjYXQoIlxuIFxuIikKfQpgYGAKCiMjIyB7LnVubGlzdGVkIC51bm51bWJlcmVkIC50YWJzZXQgLnRhYnNldC1mYWRlIC50YWJzZXQtcGlsbHN9CgpgYGB7ciBkYXRhLWV4cGxvcmF0aW9uLTIwMTgtMTksIHJlc3VsdHM9J2FzaXMnLCBjYWNoZT1UUlVFLCBlY2hvPUZBTFNFfQpmb3IgKGkgaW4gbmFtZXNfZGlzcGxheSkgewogIGNhdCgiIyMjIyIsIGksICJ7LnVubGlzdGVkIC51bm51bWJlcmVkfSBcbiIpCiAgaWYgKGkgPT0gIm1heGRlcHRoIikgewogICAgcHJpbnQoCiAgICAgIGdncGxvdCgpICsKICAgICAgICBnZW9tX3BvaW50KAogICAgICAgICAgZGF0YSA9IGRhdGFfMjAxOF9maWx0ZXJbZGF5X2RlcGFydHVyZSA8IDMyLCAuKAogICAgICAgICAgICAuaWQsCiAgICAgICAgICAgIGRheV9kZXBhcnR1cmUsCiAgICAgICAgICAgIHRoZXJtb2NsaW5lZGVwdGgKICAgICAgICAgICldLAogICAgICAgICAgYWVzKAogICAgICAgICAgICB4ID0gZGF5X2RlcGFydHVyZSwKICAgICAgICAgICAgeSA9IC10aGVybW9jbGluZWRlcHRoLAogICAgICAgICAgICBjb2xvdXIgPSAiVGhlcm1vY2xpbmUgKG0pIiwKICAgICAgICAgICAgZ3JvdXAgPSBkYXlfZGVwYXJ0dXJlCiAgICAgICAgICApLAogICAgICAgICAgYWxwaGEgPSAuMiwKICAgICAgICAgIHNpemUgPSAuNQogICAgICAgICkgKwogICAgICAgIGdlb21fcG9pbnQoCiAgICAgICAgICBkYXRhID0gZGF0YV8yMDE4X2ZpbHRlcltkYXlfZGVwYXJ0dXJlIDwgMzIsIC4oCiAgICAgICAgICAgIC5pZCwKICAgICAgICAgICAgZGF5X2RlcGFydHVyZSwKICAgICAgICAgICAgZXVwaG90aWNkZXB0aAogICAgICAgICAgKV0sCiAgICAgICAgICBhZXMoCiAgICAgICAgICAgIHggPSBkYXlfZGVwYXJ0dXJlLAogICAgICAgICAgICB5ID0gLWV1cGhvdGljZGVwdGgsCiAgICAgICAgICAgIGNvbG91ciA9ICJFdXBob3RpYyAobSkiLAogICAgICAgICAgICBncm91cCA9IGRheV9kZXBhcnR1cmUKICAgICAgICAgICksCiAgICAgICAgICBhbHBoYSA9IC4yLAogICAgICAgICAgc2l6ZSA9IC41CiAgICAgICAgKSArCiAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCgKICAgICAgICAgIHZhbHVlcyA9IGMoCiAgICAgICAgICAgICJUaGVybW9jbGluZSAobSkiID0gInJlZCIsCiAgICAgICAgICAgICJFdXBob3RpYyAobSkiID0gImJsYWNrIgogICAgICAgICAgKSwKICAgICAgICAgIG5hbWUgPSAiWm9uZSIKICAgICAgICApICsKICAgICAgICBuZXdfc2NhbGVfY29sb3IoKSArCiAgICAgICAgZ2VvbV9ib3hwbG90KAogICAgICAgICAgZGF0YSA9IG1lbHQoZGF0YV8yMDE4X2ZpbHRlcltkYXlfZGVwYXJ0dXJlIDwgMzIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuKC5pZCwgZGF5X2RlcGFydHVyZSwgZ2V0KGkpKV0sIAogICAgICAgICAgICAgICAgICAgICAgaWQudmFycyA9IGMoIi5pZCIsICJkYXlfZGVwYXJ0dXJlIikpLAogICAgICAgICAgYWVzKAogICAgICAgICAgICB4ID0gZGF5X2RlcGFydHVyZSwKICAgICAgICAgICAgeSA9IC12YWx1ZSwKICAgICAgICAgICAgY29sID0gLmlkLAogICAgICAgICAgICBncm91cCA9IGRheV9kZXBhcnR1cmUKICAgICAgICAgICksCiAgICAgICAgICBhbHBoYSA9IDEgLyAxMCwKICAgICAgICAgIHNpemUgPSAuNSwKICAgICAgICAgIHNob3cubGVnZW5kID0gRkFMU0UKICAgICAgICApICsKICAgICAgICBmYWNldF93cmFwKC4gfiAuaWQsIHNjYWxlcyA9ICJmcmVlIikgKwogICAgICAgIGxhYnMoeCA9ICIjIGRheXMgc2luY2UgZGVwYXJ0dXJlIiwgeSA9ICJNYXhpbXVtIERlcHRoIChtKSIpICsKICAgICAgICB0aGVtZV9qam8oKSArCiAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCiAgICApCiAgfSBlbHNlIHsKICAgIHByaW50KAogICAgICBnZ3Bsb3QoCiAgICAgICAgZGF0YSA9IG1lbHQoZGF0YV8yMDE4X2ZpbHRlcltkYXlfZGVwYXJ0dXJlIDwgMzIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLiguaWQsIGRheV9kZXBhcnR1cmUsIGdldChpKSldLCAKICAgICAgICAgICAgICAgICAgICBpZC52YXJzID0gYygiLmlkIiwgImRheV9kZXBhcnR1cmUiKSksCiAgICAgICAgYWVzKAogICAgICAgICAgeCA9IGRheV9kZXBhcnR1cmUsCiAgICAgICAgICB5ID0gdmFsdWUsCiAgICAgICAgICBjb2xvciA9IC5pZCwKICAgICAgICAgIGdyb3VwID0gZGF5X2RlcGFydHVyZQogICAgICAgICkKICAgICAgKSArCiAgICAgICAgZ2VvbV9ib3hwbG90KAogICAgICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRSwKICAgICAgICAgIGFscGhhID0gMSAvIDEwLAogICAgICAgICAgc2l6ZSA9IC41CiAgICAgICAgKSArCiAgICAgICAgZmFjZXRfd3JhcCguIH4gLmlkLCBzY2FsZXMgPSAiZnJlZSIpICsKICAgICAgICBsYWJzKHggPSAiIyBkYXlzIHNpbmNlIGRlcGFydHVyZSIsIHkgPSBpKSArCiAgICAgICAgdGhlbWVfampvKCkKICAgICkKICB9CiAgY2F0KCJcbiBcbiIpCn0KYGBgCgojIyMgey51bmxpc3RlZCAudW5udW1iZXJlZH0KCmBgYHtyIGRhdGEtZXhwbG9yYXRpb24tMjAxOC0yMCwgZXZhbD1GQUxTRSwgaW5jbHVkZT1UUlVFfQpmb3IgKGkgaW4gbmFtZXNfZGlzcGxheSkgewogIGNhdCgiIyMjIyIsIGksICJ7LnVubGlzdGVkIC51bm51bWJlcmVkfSBcbiIpCiAgcHJpbnQoCiAgICBnZ3Bsb3QoCiAgICAgIGRhdGEgPSBtZWx0KGRhdGFfMjAxOF9maWx0ZXJbCiAgICAgICAgZGF5X2RlcGFydHVyZSA8IDMyLAogICAgICAgIC4oLmlkLCBkYXlfZGVwYXJ0dXJlLCBnZXQoaSksIHBoYXNlKQogICAgICBdLAogICAgICBpZC52YXJzID0gYygiLmlkIiwgImRheV9kZXBhcnR1cmUiLCAicGhhc2UiKQogICAgICApLAogICAgICBhZXMoCiAgICAgICAgeCA9IGRheV9kZXBhcnR1cmUsCiAgICAgICAgeSA9IHZhbHVlLAogICAgICAgIGNvbG9yID0gcGhhc2UsCiAgICAgICAgZ3JvdXAgPSBpbnRlcmFjdGlvbihkYXlfZGVwYXJ0dXJlLCBwaGFzZSksCiAgICAgICkKICAgICkgKwogICAgICBnZW9tX2JveHBsb3QoCiAgICAgICAgYWxwaGEgPSAxIC8gMTAsCiAgICAgICAgc2l6ZSA9IC41CiAgICAgICkgKwogICAgICBmYWNldF93cmFwKC4gfiAuaWQsIHNjYWxlcyA9ICJmcmVlIikgKwogICAgICBsYWJzKHggPSAiIyBkYXlzIHNpbmNlIGRlcGFydHVyZSIsIHkgPSBpKSArCiAgICAgIHRoZW1lX2pqbygpICsKICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCiAgKQogIGNhdCgiXG4gXG4iKQp9CmBgYAoKIyMjIHsudW5saXN0ZWQgLnVubnVtYmVyZWQgLnRhYnNldCAudGFic2V0LWZhZGUgLnRhYnNldC1waWxsc30KCmBgYHtyIGRhdGEtZXhwbG9yYXRpb24tMjAxOC0yMSwgcmVzdWx0cz0nYXNpcycsIGNhY2hlPVRSVUUsIGVjaG89RkFMU0V9CmZvciAoaSBpbiBuYW1lc19kaXNwbGF5KSB7CiAgY2F0KCIjIyMjIiwgaSwgInsudW5saXN0ZWQgLnVubnVtYmVyZWR9IFxuIikKICBwcmludCgKICAgIGdncGxvdCgKICAgICAgZGF0YSA9IG1lbHQoZGF0YV8yMDE4X2ZpbHRlclsKICAgICAgICBkYXlfZGVwYXJ0dXJlIDwgMzIsCiAgICAgICAgLiguaWQsIGRheV9kZXBhcnR1cmUsIGdldChpKSwgcGhhc2UpCiAgICAgIF0sCiAgICAgIGlkLnZhcnMgPSBjKCIuaWQiLCAiZGF5X2RlcGFydHVyZSIsICJwaGFzZSIpCiAgICAgICksCiAgICAgIGFlcygKICAgICAgICB4ID0gZGF5X2RlcGFydHVyZSwKICAgICAgICB5ID0gdmFsdWUsCiAgICAgICAgY29sb3IgPSBwaGFzZSwKICAgICAgICBncm91cCA9IGludGVyYWN0aW9uKGRheV9kZXBhcnR1cmUsIHBoYXNlKSwKICAgICAgKQogICAgKSArCiAgICAgIGdlb21fYm94cGxvdCgKICAgICAgICBhbHBoYSA9IDEgLyAxMCwKICAgICAgICBzaXplID0gLjUKICAgICAgKSArCiAgICAgIGZhY2V0X3dyYXAoLiB+IC5pZCwgc2NhbGVzID0gImZyZWUiKSArCiAgICAgIGxhYnMoeCA9ICIjIGRheXMgc2luY2UgZGVwYXJ0dXJlIiwgeSA9IGkpICsKICAgICAgdGhlbWVfampvKCkgKwogICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKICApCiAgY2F0KCJcbiBcbiIpCn0KYGBgCgojIyMgQ29ycmVsYXRpb24KCkNhbiB3ZSBmaW5kIG5pY2UgY29ycmVsYXRpb24/CiAgCmBgYHtyIGRhdGEtZXhwbG9yYXRpb24tMjAxOC0yMiwgZmlnLmNhcD0iQ29ycmVsYXRpb24gbWF0cml4IChjcm9zc2VzIGluZGljYXRlIG5vbiBzaWduaWZpY2FudCBjb3JyZWxhdGlvbikiLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTB9CiMgY29tcHV0ZSBjb3JyZWxhdGlvbgpjb3JyXzIwMTggPC0gcm91bmQoY29yKGRhdGFfMjAxOF9maWx0ZXJbLCBuYW1lc19kaXNwbGF5LCB3aXRoID0gRl0sCiAgICAgICAgICAgICAgICAgICAgICAgdXNlID0gInBhaXJ3aXNlLmNvbXBsZXRlLm9icyIKKSwgMSkKCiMgcmVwbGFjZSBOQSB2YWx1ZSBieSAwCmNvcnJfMjAxOFtpcy5uYShjb3JyXzIwMTgpXSA8LSAwCgojIGNvbXB1dGUgcF92YWx1ZXMKY29ycl9wXzIwMTggPC0gY29yX3BtYXQoZGF0YV8yMDE4X2ZpbHRlclssIG5hbWVzX2Rpc3BsYXksIHdpdGggPSBGXSkKCiMgcmVwbGFjZSBOQSB2YWx1ZSBieSAwCmNvcnJfcF8yMDE4W2lzLm5hKGNvcnJfcF8yMDE4KV0gPC0gMQoKIyBkaXNwbGF5CmdnY29ycnBsb3QoCiAgY29ycl8yMDE4LAogIHAubWF0ID0gY29ycl9wXzIwMTgsCiAgaGMub3JkZXIgPSBUUlVFLAogIG1ldGhvZCA9ICJjaXJjbGUiLAogIHR5cGUgPSAibG93ZXIiLAogIGdndGhlbWUgPSB0aGVtZV9qam8oKSwKICBzaWcubGV2ZWwgPSAwLjA1LAogIGNvbG9ycyA9ICBjKCIjMDBBRkJCIiwgIiNFN0I4MDAiLCAiI0ZDNEUwNyIpCikKYGBgCgpBbm90aGVyIHdheSB0byBzZWUgaXQ6CiAgCmBgYHtyIGRhdGEtZXhwbG9yYXRpb24tMjAxOC0yM30KIyBmbGF0dGVuIGNvcnJlbGF0aW9uIG1hdHJpeApjb3JfcmVzdWx0XzIwMTggPC0gZmxhdF9jb3JfbWF0KGNvcnJfMjAxOCwgY29ycl9wXzIwMTgpCgojIGtlZXAgb25seSB0aGUgb25lIGFib3ZlIC43CmNvcl9yZXN1bHRfMjAxOFtjb3IgPj0gLjcsIF1bb3JkZXIoLWFicyhjb3IpKV0gJT4lCiAgc2FibGUoY2FwdGlvbiA9ICJQYWlyd2lzZSBjb3JyZWxhdGlvbiBhYm92ZSAwLjc1IGFuZCBhc3NvY2lhdGVkIHAtdmFsdWVzIikKYGBgCgo+IEkgZ3Vlc3Mgbm90aGluZyB1bmV4cGVjdGVkIGhlcmUsIEknbGwgaGF2ZSB0byBjaGVjayB3aXRoIFBhdHJpY2sgYWJvdXQgdGhlIGVmZmljaWVuY3kgOykKCiMjIERpdmUgVHlwZQoKYGBge3IgZGF0YS1leHBsb3JhdGlvbi0yMDE4LTI0LCBmaWcuY2FwPSJQcm9wb3J0aW9uIGRpdmUgdHlwZXMifQojIGRhdGFzZXQgdG8gcGxvdCBwcm9wb3J0aW9uYWwgYXJlYSBwbG90CmRhdGFfMjAxOF9maWx0ZXJbLCBzdW1faWQgOj0gLk4sIGJ5ID0gLiguaWQsIGRheV9kZXBhcnR1cmUpXSAlPiUKICAuWywgc3VtX2lkX2RheXMgOj0gLk4sIGJ5ID0gLiguaWQsIGRheV9kZXBhcnR1cmUsIGRpdmV0eXBlKV0gJT4lCiAgLlssIHByb3AgOj0gc3VtX2lkX2RheXMgLyBzdW1faWRdCmRhdGFQbG90IDwtIHVuaXF1ZShkYXRhXzIwMThfZmlsdGVyWywgLihwcm9wLCAuaWQsIGRpdmV0eXBlLCBkYXlfZGVwYXJ0dXJlKV0pCgojIGFyZWEgcGxvdApnZ3Bsb3QoZGF0YVBsb3QsIGFlcygKICB4ID0gYXMubnVtZXJpYyhkYXlfZGVwYXJ0dXJlKSwKICB5ID0gcHJvcCwKICBmaWxsID0gYXMuY2hhcmFjdGVyKGRpdmV0eXBlKQopKSArCiAgZ2VvbV9hcmVhKGFscGhhID0gMC42LCBzaXplID0gMSkgKwogIGZhY2V0X3dyYXAoLmlkIH4gLiwgc2NhbGVzID0gImZyZWUiKSArCiAgdGhlbWVfampvKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgbGFicyh4ID0gIiMgb2YgZGF5cyBzaW5jZSBkZXBhcnR1cmUiLCAKICAgICAgIHkgPSAiUHJvcG9ydGlvbiBvZiBkaXZlcyIsIAogICAgICAgZmlsbCA9ICJEaXZlIHR5cGVzIikKYGBgCgojIyBEaXZlIGR1cmF0aW9uICp2cy4qIE1heGltdW0gZGVwdGggey50YWJzZXR9CgojIyMgQ29sb3JlZCBieSBJRAoKYGBge3IgZGF0YS1leHBsb3JhdGlvbi0yMDE4LTI1LCBmaWcuY2FwPSJEaXZlIGR1cmF0aW9uIHZzLiBNYXhpbXVtIERlcHRoIGNvbG9yZWQgMjAxOC1pbmRpdmlkdWFscyJ9CiMgcGxvdApnZ3Bsb3QoZGF0YSA9IGRhdGFfMjAxOF9maWx0ZXIsIGFlcyh5ID0gZGR1cmF0aW9uLCB4ID0gbWF4ZGVwdGgsIGNvbCA9IC5pZCkpICsKICBnZW9tX3BvaW50KHNpemUgPSAuNSwgYWxwaGEgPSAuMSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGZhY2V0X3dyYXAoLmlkIH4gLikgKwogIGxhYnMoeCA9ICJNYXhpbXVtIGRlcHRoIChtKSIsIHkgPSAiRGl2ZSBkdXJhdGlvbiAocykiKSArCiAgdGhlbWVfampvKCkKYGBgCgojIyMgQ29sb3JlZCBieSBEaXZlIFR5cGUKCmBgYHtyIGRhdGEtZXhwbG9yYXRpb24tMjAxOC0yNiwgZmlnLmNhcD0iRGl2ZSBkdXJhdGlvbiB2cy4gTWF4aW11bSBEZXB0aCBjb2xvcmVkIGJ5IERpdmUgVHlwZSJ9CiMgcGxvdApnZ3Bsb3QoZGF0YSA9IGRhdGFfMjAxOF9maWx0ZXIsIGFlcyh5ID0gZGR1cmF0aW9uLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9IG1heGRlcHRoLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gZGl2ZXR5cGUpKSArCiAgZ2VvbV9wb2ludChzaXplID0gLjUsIGFscGhhID0gLjEpICsKICBmYWNldF93cmFwKC5pZCB+IC4pICsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDUsIGFscGhhID0gMSkpKSArCiAgbGFicyh4ID0gIk1heGltdW0gZGVwdGggKG0pIiwgeSA9ICJEaXZlIGR1cmF0aW9uIChzKSIpICsKICB0aGVtZV9qam8oKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCmBgYAoKIyMjIENvbG9yZWQgYnkgIyBkYXlzIHNpbmNlIGRlcGFydHVyZQoKYGBge3IgZGF0YS1leHBsb3JhdGlvbi0yMDE4LTI3LCBmaWcuY2FwPSJEaXZlIGR1cmF0aW9uIHZzLiBNYXhpbXVtIERlcHRoIGNvbG9yZWQgYnkgIyBkYXlzIHNpbmNlIGRlcGFydHVyZSJ9CiMgcGxvdApnZ3Bsb3QoZGF0YSA9IGRhdGFfMjAxOF9maWx0ZXJbLCBwcm9wX3RyYWNrIDo9IChkYXlfZGVwYXJ0dXJlICogMTAwKSAvIG1heChkYXlfZGVwYXJ0dXJlKSwgYnkgPSAuaWRdLCAKICAgICAgIGFlcyh5ID0gZGR1cmF0aW9uLCB4ID0gbWF4ZGVwdGgsIGNvbCA9IHByb3BfdHJhY2spKSArCiAgZ2VvbV9wb2ludChzaXplID0gLjUsIGFscGhhID0gLjEpICsKICBmYWNldF93cmFwKC5pZCB+IC4pICsKICBsYWJzKHggPSAiTWF4aW11bSBkZXB0aCAobSkiLCAKICAgICAgIHkgPSAiRGl2ZSBkdXJhdGlvbiAocykiLCAKICAgICAgIGNvbCA9ICJQcm9wb3J0aW9uIG9mIGNvbXBsZXRlZCB0cmFjayAoJSkiKSArCiAgc2NhbGVfY29sb3JfY29udGludW91cyh0eXBlID0gInZpcmlkaXMiKSArCiAgdGhlbWVfampvKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQpgYGAKCiMjIyBDb2xvcmVkIGJ5IHBoYXNlcyBvZiBkYXkKCmBgYHtyIGRhdGEtZXhwbG9yYXRpb24tMjAxOC0yOCwgZmlnLmNhcD0iRGl2ZSBkdXJhdGlvbiB2cy4gTWF4aW11bSBEZXB0aCBjb2xvcmVkIGJ5IHBoYXNlcyBvZiB0aGUgZGF5In0KIyBwbG90CmdncGxvdChkYXRhID0gZGF0YV8yMDE4X2ZpbHRlciwgYWVzKHkgPSBkZHVyYXRpb24sIHggPSBtYXhkZXB0aCwgY29sID0gcGhhc2UpKSArCiAgZ2VvbV9wb2ludChzaXplID0gLjUsIGFscGhhID0gLjEpICsKICBmYWNldF93cmFwKC5pZCB+IC4pICsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDUsIGFscGhhID0gMSkpKSArCiAgbGFicyh4ID0gIk1heGltdW0gZGVwdGggKG0pIiwgCiAgICAgICB5ID0gIkRpdmUgZHVyYXRpb24gKHMpIiwgCiAgICAgICBjb2wgPSAiUGhhc2VzIG9mIHRoZSBkYXkiKSArCiAgdGhlbWVfampvKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQpgYGAKCj4gVGhlcmUgc2VlbXMgdG8gYmUgYSAqcGF0Y2gqIGZvciBoaWdoIGRlcHRocyAoZXNwZWNpYWxseSB2aXNpYmxlIGZvciBgaW5kMjAxODA3MGApLCBidXQgSSBkb24ndCBrbm93IHdoYXQgaXQgY291bGQgYmUgbGlua2VkIHRvLi4uCgojIyBEcmlmdCBSYXRlCgo+IEluIHRoZSBmb2xsb3dpbmcgZ3JhcGhzOgo+Cj4gKiBgZHJpZnRyYXRlYCBpcyBjYWxjdWxhdGVkIHVzaW5nIG9ubHkgYGRpdmV0eXBlID09ICIyOiBkcmlmdCJgCj4gKiB3aGVyZWFzIGFsbCB0aGUgb3RoZXJzIHZhcmlhYmxlcyBhcmUgY2FsY3VsYXRlZCBhbGwgZGl2ZXMgY29uc2lkZXJlZAoKYGBge3IgZGF0YS1leHBsb3JhdGlvbi0yMDE4LTI5fQojIGJ1aWxkIGRhdGFzZXQKZGF0YVBsb3QgPC0gZGF0YV8yMDE4X2ZpbHRlcltkaXZldHlwZSA9PSAiMjogZHJpZnQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgbWVkaWFuIGRyaWZ0IHJhdGUgZm9yIGRyaWZ0IGRpdmUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuKGRyaWZ0cmF0ZSA9IG1lZGlhbihkcmlmdHJhdGUsIG5hLnJtID0gVCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gLiguaWQsIGRheV9kZXBhcnR1cmUpCl1bZGF0YV8yMDE4X2ZpbHRlclssCiAgICAgICAgICAgICAgICAgICAuKAogICAgICAgICAgICAgICAgICAgICAjIG1lZGlhbiBkaXZlIGR1cmF0aW9uIGFsbCBkaXZlcyBjb25zaWRlcmVkCiAgICAgICAgICAgICAgICAgICAgIGRkdXJhdGlvbiA9IG1lZGlhbihkZHVyYXRpb24sIG5hLnJtID0gVCksCiAgICAgICAgICAgICAgICAgICAgICMgbWVkaWFuIG1heCBkZXB0aCBhbGwgZGl2ZXMgY29uc2lkZXJlZAogICAgICAgICAgICAgICAgICAgICBtYXhkZXB0aCA9IG1lZGlhbihtYXhkZXB0aCwgbmEucm0gPSBUKSwKICAgICAgICAgICAgICAgICAgICAgIyBtZWRpYW4gYm90dG9tIGRpdmVzIGFsbCBkaXZlcyBjb25zaWRlcmVkCiAgICAgICAgICAgICAgICAgICAgIGJvdHR0aW1lID0gbWVkaWFuKGJvdHR0aW1lLCBuYS5ybSA9IFQpCiAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgICAgYnkgPSAuKC5pZCwgZGF5X2RlcGFydHVyZSkKXSwKb24gPSBjKCIuaWQiLCAiZGF5X2RlcGFydHVyZSIpCl0KYGBgCgpgYGB7ciBkYXRhLWV4cGxvcmF0aW9uLTIwMTgtMzAsIGZpZy5jYXA9IkRyaWZ0IHJhdGUgdnMuIEJvdHRvbSB0aW1lIn0KIyBwbG90CmdncGxvdChkYXRhUGxvdCwgYWVzKHggPSBib3R0dGltZSwgeSA9IGRyaWZ0cmF0ZSwgY29sID0gLmlkKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IC41LCBhbHBoYSA9IC41KSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIikgKwogIGd1aWRlcyhjb2xvciA9ICJub25lIikgKwogIGZhY2V0X3dyYXAoLmlkIH4gLikgKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDcwMCkpICsKICBsYWJzKHggPSAiRGFpbHkgbWVkaWFuIEJvdHRvbSB0aW1lIChzKSIsIAogICAgICAgeSA9ICJEYWlseSBtZWRpYW4gZHJpZnQgcmF0ZSAobS5zLTEpIikgKwogIHRoZW1lX2pqbygpCmBgYAoKYGBge3IgZGF0YS1leHBsb3JhdGlvbi0yMDE4LTMxLCBmaWcuY2FwPSJEcmlmdCByYXRlIHZzLiBNYXhpbXVtIGRlcHRoIn0KIyBwbG90CmdncGxvdChkYXRhUGxvdCwgYWVzKHggPSBtYXhkZXB0aCwgeSA9IGRyaWZ0cmF0ZSwgY29sID0gLmlkKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IC41LCBhbHBoYSA9IC41KSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIikgKwogIGd1aWRlcyhjb2xvciA9ICJub25lIikgKwogIGZhY2V0X3dyYXAoLmlkIH4gLikgKwogIGxhYnMoeCA9ICJEYWlseSBtZWRpYW4gTWF4aW11bSBkZXB0aCAobSkiLCAKICAgICAgIHkgPSAiRGFpbHkgbWVkaWFuIGRyaWZ0IHJhdGUgKG0ucy0xKSIpICsKICB0aGVtZV9qam8oKQpgYGAKCmBgYHtyIGRhdGEtZXhwbG9yYXRpb24tMjAxOC0zMiwgZmlnLmNhcD0iRHJpZnQgcmF0ZSB2cy4gRGl2ZSBkdXJhdGlvbiJ9CiMgcGxvdApnZ3Bsb3QoZGF0YVBsb3QsIGFlcyh4ID0gZGR1cmF0aW9uLCB5ID0gZHJpZnRyYXRlLCBjb2wgPSAuaWQpKSArCiAgZ2VvbV9wb2ludChzaXplID0gLjUsIGFscGhhID0gLjUpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKSArCiAgZ3VpZGVzKGNvbG9yID0gIm5vbmUiKSArCiAgZmFjZXRfd3JhcCguaWQgfiAuKSArCiAgbGFicyh4ID0gIkRhaWx5IG1lZGlhbiBEaXZlIGR1cmF0aW9uIChzKSIsIAogICAgICAgeSA9ICJEYWlseSBtZWRpYW4gZHJpZnQgcmF0ZSAobS5zLTEpIikgKwogIHRoZW1lX2pqbygpCmBgYAoKIyMgQmVoYXZpb3JhbCBBZXJvYmljIERpdmUgTGltaXQgKGJBREwpCgojIyMgW0Nvb2sgZXQgYWwgKDIwMDgpXShodHRwczovL3d3dy5zY2llbmNlZGlyZWN0LmNvbS9zY2llbmNlL2FydGljbGUvcGlpL1MwMDAzMzQ3MjA4MDAxMzZYP3ZpYSUzRGlodWIpCgpgYGB7ciBkYXRhLWV4cGxvcmF0aW9uLTIwMTgtMzMsIGZpZy5jYXA9IlBvc3QtZGl2ZSBkdXJhdGlvbiB2cy4gZGl2ZSBkdXJhdGlvbiJ9CiMgZGl2ZSBkdXJhdGlvbiB2cyBwZGkgYnkgZGF5cwpnZ3Bsb3QoZGF0YSA9IGRhdGFfMjAxOF9maWx0ZXJbcGRpIDwgMzAwLCBdLCBhZXMoCiAgeCA9IGRkdXJhdGlvbiwKICB5ID0gcGRpLAogIGNvbG9yID0gLmlkLAogIGdyb3VwID0gZGR1cmF0aW9uLAogIGZpbGwgPSAibm9uZSIKKSkgKwogIGdlb21fYm94cGxvdChzaG93LmxlZ2VuZCA9IEZBTFNFLCBvdXRsaWVyLmFscGhhID0gMC4wNSwgYWxwaGEgPSAwKSArCiAgbGFicyh4ID0gIkRpdmUgZHVyYXRpb24gKHMpIiwgeSA9ICJQb3N0LWRpdmUgZHVyYXRpb24gKHMpIikgKwogIGZhY2V0X3dyYXAoLiB+IC5pZCwgc2NhbGVzID0gImZyZWVfeCIpICsKICB0aGVtZV9qam8oKQpgYGAKCmBgYHtyIGRhdGEtZXhwbG9yYXRpb24tMjAxOC0zNCwgZmlnLmNhcD0iUG9zdC1kaXZlIGR1cmF0aW9uIHZzLiBkaXZlIGR1cmF0aW9uIChyYXcgZGF0YSkifQojIGRpdmUgZHVyYXRpb24gdnMgcGRpIGJ5IGRheXMKZ2dwbG90KGRhdGEgPSBkYXRhXzIwMThfZmlsdGVyW3BkaSA8IDMwMCxdLCBhZXMoeCA9IGRkdXJhdGlvbiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBwZGksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IC5pZCkpICsKICBnZW9tX3BvaW50KHNob3cubGVnZW5kID0gRkFMU0UsIGFscGhhID0gMC4wNSkgKwogIGdlb21fc21vb3RoKAogICAgbWV0aG9kID0gImdhbSIsCiAgICBzaG93LmxlZ2VuZCA9IEZBTFNFLAogICAgY29sID0gImJsYWNrIiwKICAgIGxpbmV0eXBlID0gImRhc2hlZCIKICApICsKICBsYWJzKHggPSAiRGl2ZSBkdXJhdGlvbiAocykiLCB5ID0gIlBvc3QtZGl2ZSBkdXJhdGlvbiAocykiKSArCiAgZmFjZXRfd3JhcCguIH4gLmlkLCBzY2FsZXMgPSAiZnJlZV94IikgKwogIHRoZW1lX2pqbygpCmBgYApgYGB7ciBkYXRhLWV4cGxvcmF0aW9uLTIwMTgtMzUsIGZpZy5jYXA9IlBvc3QtZGl2ZSBkdXJhdGlvbiAvIGRpdmUgZHVyYXRpb24gcmF0aW8gdnMuIGRheSBzaW5jZSBkZXBhcnR1cmUifQojIGRpdmUgZHVyYXRpb24gdnMgcGRpIGJ5IGRheXMKZ2dwbG90KAogIGRhdGEgPSBkYXRhXzIwMThfZmlsdGVyW3BkaSA8IDMwMCwgLiguaWQsIHBkaV9yYXRpbyA9IHBkaSAvIGRkdXJhdGlvbiwgZGF5X2RlcGFydHVyZSldLAogIGFlcygKICAgIHggPSBkYXlfZGVwYXJ0dXJlLAogICAgeSA9IHBkaV9yYXRpbywKICAgIGNvbG9yID0gLmlkLAogICAgZ3JvdXAgPSBkYXlfZGVwYXJ0dXJlLAogICAgZmlsbCA9ICJub25lIgogICkKKSArCiAgZ2VvbV9ib3hwbG90KHNob3cubGVnZW5kID0gRkFMU0UsCiAgICAgICAgICAgICAgIG91dGxpZXIuYWxwaGEgPSAwLjA1LAogICAgICAgICAgICAgICBhbHBoYSA9IDApICsKICBsYWJzKHggPSAiIyBkYXlzIHNpbmNlIGRlcGFydHVyZSIsIHkgPSAiUG9zdC1kaXZlIC8gRGl2ZSBkdXJhdGlvbiByYXRpbyIpICsKICBmYWNldF93cmFwKC4gfiAuaWQsIHNjYWxlcyA9ICJmcmVlX3giKSArCiAgIyB6b29tCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKDAsIDAuNCkpICsKICB0aGVtZV9qam8oKQpgYGAKCiMjIyBbU2hlcm8gZXQgKmFsLiogKDIwMTgpXShodHRwczovL3d3dy5yZXNlYXJjaGdhdGUubmV0L3B1YmxpY2F0aW9uLzIyMjY4MzA0Ml9Ub19icmVhdGhlX29yX25vdF90b19icmVhdGhlX09wdGltYWxfYnJlYXRoaW5nX2Flcm9iaWNfZGl2ZV9saW1pdF9hbmRfb3h5Z2VuX3N0b3Jlc19pbl9kZWVwLWRpdmluZ19ibHVlLWV5ZWRfc2hhZ3MpCgpCYXNlZCBvbiBbU2hlcm8gZXQgKmFsLiogKDIwMTgpXShodHRwczovL3d3dy5yZXNlYXJjaGdhdGUubmV0L3B1YmxpY2F0aW9uLzIyMjY4MzA0Ml9Ub19icmVhdGhlX29yX25vdF90b19icmVhdGhlX09wdGltYWxfYnJlYXRoaW5nX2Flcm9iaWNfZGl2ZV9saW1pdF9hbmRfb3h5Z2VuX3N0b3Jlc19pbl9kZWVwLWRpdmluZ19ibHVlLWV5ZWRfc2hhZ3MpLCB3ZSBkZWNpZGVkIHRvIGxvb2sgYXQgdGhlICpiQURMKiBhcyB0aGUgOTV0aCBwZXJjZW50aWxlIG9mIGRpdmUgZHVyYXRpb24gZWFjaCBkYXksIGZvciB0aG9zZSB3aXRoICRuIFxnZXEgNTAkLiBUaGlzIHRocmVzaG9sZCB3YXMgY2hvc2VuIGZvbGxvd2luZyB0aGlzIGZpZ3VyZToKCmBgYHtyIGRhdGEtZXhwbG9yYXRpb24tMjAxOC0zNiwgZmlnLmNhcD0iRGlzdHJpYnV0aW9uIG9mIHRoZSBudW1iZXIgb2YgZGl2ZXMgZWFjaCBkYXkuIFRoZSB0aHJlc2hvbGQgdXNlZCB0byBjYWxjdWxhdGUgYkFETCBpcyBmaXhlZCBhdCA1MCBkaXZlcyBwZXIgZGF5LiIsIGZpZy5oZWlnaHQ9M30KZ2dwbG90KGRhdGFfMjAxOF9maWx0ZXJbLC4obmJfZGl2ZXMgPSAuTiksIAogICAgICAgICAgICAgICAgICAgICAgICBieSA9IC4oLmlkLCBkYXlfZGVwYXJ0dXJlKV0sIAogICAgICAgYWVzKHg9bmJfZGl2ZXMsIGZpbGw9LmlkKSkgKwogIGdlb21faGlzdG9ncmFtKHNob3cubGVnZW5kID0gRkFMU0UpICsgCiAgZmFjZXRfZ3JpZCgufi5pZCkgKwogIGxhYnMoeT0iIyBvZiBkYXlzIiwgeCA9ICIjIG9mIGRpdmVzIHBlciBkYXkiKSArCiAgdGhlbWVfampvKCkKYGBgCgpgYGB7ciBkYXRhLWV4cGxvcmF0aW9uLTIwMTgtMzcsIGZpZy5jYXA9IkJlaGF2aW9yYWwgQURMIHZzLiBkcmlmdCByYXRlIGFsb25nIGFuaW1hbHMnIHRyaXAgKEFtIEkgdGhlIG9ubHkgb25lIHNlZWluZyBzb21lIGtpbmQgb2YgcmVsYXRpb25zaGlwPykifQojIHNlbGVjdCBkYXkgdGhhdCBoYXZlIGF0IGxlYXN0IDUwIGRpdmVzCmRheXNfdG9fa2VlcCA9IGRhdGFfMjAxOF9maWx0ZXJbLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4obmJfZGl2ZXMgPSAuTiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSAuKC5pZCwgZGF5X2RlcGFydHVyZSldICU+JQogIC5bbmJfZGl2ZXMgPj0gNTAsXQoKIyBrZWVwIG9ubHkgdGhvc2UgZGF5cwpkYXRhXzIwMThfZmlsdGVyX2NvbXBsZXRlX2RheSA9IG1lcmdlKGRhdGFfMjAxOF9maWx0ZXIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c190b19rZWVwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gYygiLmlkIiwgImRheV9kZXBhcnR1cmUiKSkKCiMgZGF0YSBwbG90CmRhdGFQbG90ID0gZGF0YV8yMDE4X2ZpbHRlcl9jb21wbGV0ZV9kYXlbLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4oYmFkbCA9IHF1YW50aWxlKGRkdXJhdGlvbiwgMC45NSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gLiguaWQsIGRheV9kZXBhcnR1cmUpXQoKIyBjb21iaW5lIHR3byBkYXRhc2V0cyB0byBiZSBhYmxlIHRvIHVzZSBhIHNlY29uZCBheGlzCiMgaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvNDkxODU1ODMvdHdvLXktYXhlcy13aXRoLWRpZmZlcmVudC1zY2FsZXMtZm9yLXR3by1kYXRhc2V0cy1pbi1nZ3Bsb3QyCmRhdGFNZWdhUGxvdCA9IHJiaW5kKGRhdGFfMjAxOF9maWx0ZXJfY29tcGxldGVfZGF5W2RpdmV0eXBlID09ICIyOiBkcmlmdCJdICU+JQogICAgICAgICAgICAgICAgICAgICAgIC5bLCAuKHcgPSAuaWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGRyaWZ0cmF0ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gZGF5X2RlcGFydHVyZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB6ID0gInNlY29uZF9wbG90IildLAogICAgICAgICAgICAgICAgICAgICBkYXRhUGxvdFssIC4oCiAgICAgICAgICAgICAgICAgICAgICAgdyA9IC5pZCwKICAgICAgICAgICAgICAgICAgICAgICAjIHRyaWNreSBvbmUKICAgICAgICAgICAgICAgICAgICAgICB5ID0gKGJhZGwgLyAxMDAwKSAtIDEsCiAgICAgICAgICAgICAgICAgICAgICAgeCA9IGRheV9kZXBhcnR1cmUsCiAgICAgICAgICAgICAgICAgICAgICAgeiA9ICJmaXJzdF9wbG90IgogICAgICAgICAgICAgICAgICAgICApXSkKCiMgcGxvdApnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludCgKICAgIGRhdGEgPSBkYXRhTWVnYVBsb3RbeiA9PSAic2Vjb25kX3Bsb3QiLCBdLAogICAgYWVzKHggPSB4LCB5ID0geSksCiAgICBhbHBoYSA9IDEgLyAxMCwKICAgIHNpemUgPSAwLjUsCiAgICBjb2xvciA9ICJncmV5NDAiLAogICAgc2hvdy5sZWdlbmQgPSBGQUxTRQogICkgKwogIGdlb21fcGF0aChkYXRhID0gZGF0YU1lZ2FQbG90W3ogPT0gImZpcnN0X3Bsb3QiLCBdLAogICAgICAgICAgICBhZXMoeCA9IHgsIHkgPSB5LCBjb2xvciA9IHcpLAogICAgICAgICAgICBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgc2NhbGVfeV9jb250aW51b3VzKAogICAgIyBGZWF0dXJlcyBvZiB0aGUgZmlyc3QgYXhpcwogICAgbmFtZSA9ICJEcmlmdCByYXRlIChtL3MpIiwKICAgICMgQWRkIGEgc2Vjb25kIGF4aXMgYW5kIHNwZWNpZnkgaXRzIGZlYXR1cmVzCiAgICBzZWMuYXhpcyA9IHNlY19heGlzKCB+ICguICogMTAwMCkgKyAxMDAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiQmVoYXZpb3JhbCBBZXJvYmljIERpdmUgTGltaXQgKHMpIikKICApICsKICBsYWJzKHggPSAiIyBkYXlzIHNpbmNlIGRlcGFydHVyZSIpICsKICBmYWNldF93cmFwKHcgfiAuKSArCiAgdGhlbWVfampvKCkKYGBgCgo+IExvb2tpbmcgYXQgdGhpcyBncmFwaCwgSSB3YW50IHRvIGJlbGlldmUgdGhhdCB0aGVyZSBpcyBzb21lIGtpbmQgb2YgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlICpiQURMKiBhcyBkZWZpbmVkIGJ5IFtTaGVybyBldCAqYWwuKiAoMjAxOCldKGh0dHBzOi8vd3d3LnJlc2VhcmNoZ2F0ZS5uZXQvcHVibGljYXRpb24vMjIyNjgzMDQyX1RvX2JyZWF0aGVfb3Jfbm90X3RvX2JyZWF0aGVfT3B0aW1hbF9icmVhdGhpbmdfYWVyb2JpY19kaXZlX2xpbWl0X2FuZF9veHlnZW5fc3RvcmVzX2luX2RlZXAtZGl2aW5nX2JsdWUtZXllZF9zaGFncykgYW5kIHRoZSBkcmlmdCByYXRlIChhbmQgc28gYnV5b2FuY3kpLgoKYGBge3IgZGF0YS1leHBsb3JhdGlvbi0yMDE4LTM4fQojIGdldCBiYWRsCmRhdGFwbG90XzEgPSBkYXRhXzIwMThfZmlsdGVyX2NvbXBsZXRlX2RheVssCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4oYmFkbCA9IHF1YW50aWxlKGRkdXJhdGlvbiwgMC45NSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBieSA9IC4oLmlkLCBkYXlfZGVwYXJ0dXJlKV0KIyBnZXQgZHJpZnRyYXRlCmRhdGFwbG90XzIgPSBkYXRhXzIwMThfZmlsdGVyX2NvbXBsZXRlX2RheVtkaXZldHlwZSA9PSAiMjogZHJpZnQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuKGRyaWZ0cmF0ZSA9IG1lZGlhbihkcmlmdHJhdGUpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSAuKC5pZCwgZGF5X2RlcGFydHVyZSldCgojIG1lcmdlCmRhdGFQbG90ID0gbWVyZ2UoZGF0YXBsb3RfMSwKICAgICAgICAgICAgICAgICBkYXRhcGxvdF8yLAogICAgICAgICAgICAgICAgIGJ5ID0gYygiLmlkIiwgImRheV9kZXBhcnR1cmUiKSwKICAgICAgICAgICAgICAgICBhbGwgPSBUUlVFKQoKIyBwbG90CmdncGxvdChkYXRhID0gZGF0YVBsb3QsIGFlcyh4ID0gYmFkbCwgeSA9IGRyaWZ0cmF0ZSwgY29sID0gLmlkKSkgKwogIGdlb21fcG9pbnQoc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGZhY2V0X3dyYXAoLmlkfi4sIHNjYWxlcyA9ICJmcmVlIikgKwogIHRoZW1lX2pqbygpCmBgYAoKIyMjIHsudW5saXN0ZWQgLnVubnVtYmVyZWQgLnRhYnNldCAudGFic2V0LWZhZGUgLnRhYnNldC1waWxsc30KCiMjIyMgaW5kXzIwMTgwNzAgey51bmxpc3RlZCAudW5udW1iZXJlZH0KCmBgYHtyIGRhdGEtZXhwbG9yYXRpb24tMjAxOC0zOX0KIyBpbmRfMjAxODA3MApwbG90X2x5KAogIHggPSBkYXRhUGxvdFsuaWQgPT0gImluZF8yMDE4MDcwIiwgYmFkbF0sCiAgeSA9IGRhdGFQbG90Wy5pZCA9PSAiaW5kXzIwMTgwNzAiLCBkYXlfZGVwYXJ0dXJlXSwKICB6ID0gZGF0YVBsb3RbLmlkID09ICJpbmRfMjAxODA3MCIsIGRyaWZ0cmF0ZV0sCiAgdHlwZSA9ICJzY2F0dGVyM2QiLAogIG1vZGUgPSAibWFya2VycyIsCiAgbWFya2VyID0gbGlzdChzaXplID0gMiksCiAgY29sb3IgPSBkYXRhUGxvdFsuaWQgPT0gImluZF8yMDE4MDcwIiwgZGF5X2RlcGFydHVyZV0KKSAlPiUgCiAgbGF5b3V0KHNjZW5lID0gbGlzdCh4YXhpcyA9IGxpc3QodGl0bGUgPSAnQmVoYXZpb3JhbCBBREwnKSwKICAgICAgICAgICAgICAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICcjIGRheXMgc2luY2UgZGVwYXJ0dXJlJyksCiAgICAgICAgICAgICAgICAgICAgICB6YXhpcyA9IGxpc3QodGl0bGUgPSAnRHJpZnQgcmF0ZSAobS9zKScpKSkKYGBgCgojIyMjIGluZF8yMDE4MDcyIHsudW5saXN0ZWQgLnVubnVtYmVyZWR9CgpgYGB7ciBkYXRhLWV4cGxvcmF0aW9uLTIwMTgtNDB9CiMgaW5kXzIwMTgwNzIKcGxvdF9seSgKICB4ID0gZGF0YVBsb3RbLmlkID09ICJpbmRfMjAxODA3MiIsIGJhZGxdLAogIHkgPSBkYXRhUGxvdFsuaWQgPT0gImluZF8yMDE4MDcyIiwgZGF5X2RlcGFydHVyZV0sCiAgeiA9IGRhdGFQbG90Wy5pZCA9PSAiaW5kXzIwMTgwNzIiLCBkcmlmdHJhdGVdLAogIHR5cGUgPSAic2NhdHRlcjNkIiwKICBtb2RlID0gIm1hcmtlcnMiLAogIG1hcmtlciA9IGxpc3Qoc2l6ZSA9IDIpLAogIGNvbG9yID0gZGF0YVBsb3RbLmlkID09ICJpbmRfMjAxODA3MiIsIGRheV9kZXBhcnR1cmVdCikgJT4lIAogIGxheW91dChzY2VuZSA9IGxpc3QoeGF4aXMgPSBsaXN0KHRpdGxlID0gJ0JlaGF2aW9yYWwgQURMJyksCiAgICAgICAgICAgICAgICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAnIyBkYXlzIHNpbmNlIGRlcGFydHVyZScpLAogICAgICAgICAgICAgICAgICAgICAgemF4aXMgPSBsaXN0KHRpdGxlID0gJ0RyaWZ0IHJhdGUgKG0vcyknKSkpCmBgYAoKIyMjIyBpbmRfMjAxODA3NCB7LnVubGlzdGVkIC51bm51bWJlcmVkfQoKYGBge3IgZGF0YS1leHBsb3JhdGlvbi0yMDE4LTQxfQojIGluZF8yMDE4MDc0CnBsb3RfbHkoCiAgeCA9IGRhdGFQbG90Wy5pZCA9PSAiaW5kXzIwMTgwNzQiLCBiYWRsXSwKICB5ID0gZGF0YVBsb3RbLmlkID09ICJpbmRfMjAxODA3NCIsIGRheV9kZXBhcnR1cmVdLAogIHogPSBkYXRhUGxvdFsuaWQgPT0gImluZF8yMDE4MDc0IiwgZHJpZnRyYXRlXSwKICB0eXBlID0gInNjYXR0ZXIzZCIsCiAgbW9kZSA9ICJtYXJrZXJzIiwKICBtYXJrZXIgPSBsaXN0KHNpemUgPSAyKSwKICBjb2xvciA9IGRhdGFQbG90Wy5pZCA9PSAiaW5kXzIwMTgwNzQiLCBkYXlfZGVwYXJ0dXJlXQopICU+JSAKICBsYXlvdXQoc2NlbmUgPSBsaXN0KHhheGlzID0gbGlzdCh0aXRsZSA9ICdCZWhhdmlvcmFsIEFETCcpLAogICAgICAgICAgICAgICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gJyMgZGF5cyBzaW5jZSBkZXBhcnR1cmUnKSwKICAgICAgICAgICAgICAgICAgICAgIHpheGlzID0gbGlzdCh0aXRsZSA9ICdEcmlmdCByYXRlIChtL3MpJykpKQpgYGAKCiMjIyMgaW5kXzIwMTgwNzIgey51bmxpc3RlZCAudW5udW1iZXJlZH0KCmBgYHtyIGRhdGEtZXhwbG9yYXRpb24tMjAxOC00Mn0KIyBpbmRfMjAxODA4MApwbG90X2x5KAogIHggPSBkYXRhUGxvdFsuaWQgPT0gImluZF8yMDE4MDgwIiwgYmFkbF0sCiAgeSA9IGRhdGFQbG90Wy5pZCA9PSAiaW5kXzIwMTgwODAiLCBkYXlfZGVwYXJ0dXJlXSwKICB6ID0gZGF0YVBsb3RbLmlkID09ICJpbmRfMjAxODA4MCIsIGRyaWZ0cmF0ZV0sCiAgdHlwZSA9ICJzY2F0dGVyM2QiLAogIG1vZGUgPSAibWFya2VycyIsCiAgbWFya2VyID0gbGlzdChzaXplID0gMiksCiAgY29sb3IgPSBkYXRhUGxvdFsuaWQgPT0gImluZF8yMDE4MDgwIiwgZGF5X2RlcGFydHVyZV0KKSAlPiUgCiAgbGF5b3V0KHNjZW5lID0gbGlzdCh4YXhpcyA9IGxpc3QodGl0bGUgPSAnQmVoYXZpb3JhbCBBREwnKSwKICAgICAgICAgICAgICAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICcjIGRheXMgc2luY2UgZGVwYXJ0dXJlJyksCiAgICAgICAgICAgICAgICAgICAgICB6YXhpcyA9IGxpc3QodGl0bGUgPSAnRHJpZnQgcmF0ZSAobS9zKScpKSkKYGBgCgojIyBHUFMgZGF0YQoKYGBge3IgZGF0YS1leHBsb3JhdGlvbi0yMDE4LTQzLCBmaWcuY2FwPSJNYXAgd2l0aCBwb2x5bGluZXMiLCBmaWcud2lkdGg9OCwgZXZhbD1GQUxTRX0KIyBUaGlzIHBpZWNlIG9mIGNvZGUgaXMgb25seSB0aGVyZSB0byBzaG93IGhvdyB0byBkcmF3IGEgcG9seWxpbmVzIHdpdGggYSAKIyBncmFkaWVudCBjb2xvciB1c2luZyBsZWFmbGV0LldlJ3JlIG5vdCB1c2luZyBpdCBkdWUgdG8gdGhlIHNpemUgb2YgdGhlIAojIGNyZWF0ZWQgbWFwLCBhbmQgd2lsbCBjb250aW51ZSB1c2luZyBjaXJjbGUgbWFya2VyCgojIGRhdGFzZXRzIHVzZWQgdG8gZGlzcGxheSBtYXAKZGZfZHJpZnRyYXRlID0gdW5pcXVlKGRhdGFfMjAxOF9maWx0ZXJbLmlkID09ICJpbmRfMjAxODA3MCIgJiAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXZldHlwZSA9PSAiMjogZHJpZnQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLiguaWQsIGxhdCwgbG9uLCBkZHVyYXRpb24pXSkKCiMgY29sb3IgcGFsZXR0ZQpwYWwgPC0gY29sb3JOdW1lcmljKAogIHBhbGV0dGUgPSAiWWxHbkJ1IiwKICBkb21haW4gPSBkZl9kcmlmdHJhdGUkZGR1cmF0aW9uCikKCiMgYWRkIApkZl9kcmlmdHJhdGVbLCBgOj1gKG5leHRMYXQgPSBzaGlmdChsYXQpLAogICAgICAgICAgICAgICAgICAgIG5leHRMb24gPSBzaGlmdChsb24pLAogICAgICAgICAgICAgICAgICAgIGNvbG9yID0gcGFsKGRmX2RyaWZ0cmF0ZSRkZHVyYXRpb24pKV0KCiMgaW50ZXJhY3RpdmUgbWFwCmdyYWRpZW50X21hcCA8LSBsZWFmbGV0KCkgJT4lCiAgc2V0VmlldyhsbmcgPSAtMTIyLCBsYXQgPSAzOCwgem9vbSA9IDIpICU+JQogIGFkZFRpbGVzKCkgCgojIGFkZCBsaW5lcwpmb3IgKGkgaW4gMTpucm93KGRmX2RyaWZ0cmF0ZSkpIHsKICBncmFkaWVudF9tYXAgPC0gYWRkUG9seWxpbmVzKAogICAgbWFwID0gZ3JhZGllbnRfbWFwLAogICAgZGF0YSA9IGRmX2RyaWZ0cmF0ZSwKICAgIGxhdCA9IGFzLm51bWVyaWMoZGZfZHJpZnRyYXRlW2ksIGMoJ2xhdCcsICduZXh0TGF0JyldKSwKICAgIGxuZyA9IGFzLm51bWVyaWMoZGZfZHJpZnRyYXRlW2ksIGMoJ2xvbicsICduZXh0TG9uJyldKSwKICAgIGNvbG9yID0gZGZfZHJpZnRyYXRlW2ksIGNvbG9yXSwKICAgIHdlaWdodCA9IDMsCiAgICBncm91cCA9ICJpbmRpdmlkdWFsXzEiCiAgKQp9CgojIGFkZCBsYXllciBjb250cm9sCmdyYWRpZW50X21hcCA8LSBhZGRMYXllcnNDb250cm9sKAogIG1hcCA9IGdyYWRpZW50X21hcCwKICBvdmVybGF5R3JvdXBzID0gYygiaW5kaXZpZHVhbF8xIiksCiAgb3B0aW9ucyA9IGxheWVyc0NvbnRyb2xPcHRpb25zKGNvbGxhcHNlZCA9IEZBTFNFKQopCgojIGZvcm1hdChvYmplY3Quc2l6ZShncmFkaWVudF9tYXApLCB1bml0cyA9ICJNYiIpCmBgYAoKQmVjYXVzZSBmb3Igc29tZSBkYXRhIHRoZSBjb250cmFzdCBpbiBjaGFuZ2VzIHdhcyBub3QgZW5vdWdoIG1hcmtlZCwgdGhlIG9ubHkgdHJlYXRtZW50IGFwcGxpZWQgb24gdGhlc2UgZGF0YSBpcyB0byByZW1vdmUgb3V0bGllcnMgZm9yIGVhY2ggdmFyaWFibGUgdXNpbmcgdGhlIGludGVycXVhcnRpbGUgcmFuZ2UgcnVsZS4gCgpgYGB7ciBkYXRhLWV4cGxvcmF0aW9uLTIwMTgtNDR9CiMgaW50ZXJhY3RpdmUgbWFwCmdyYWRpZW50X21hcCA8LSBsZWFmbGV0KCkgJT4lCiAgc2V0VmlldyhsbmcgPSAtMTMyLCBsYXQgPSA0OCwgem9vbSA9IDQpICU+JQogIGFkZFRpbGVzKCkKCiMgbG9vcCBieSBpbmRpdmlkdWFscyBhbmQgdmFyaWFibGUKZ3JwcyA9IE5VTEwKZm9yIChpIGluIHNlcShkYXRhXzIwMThfZmlsdGVyWyFpcy5uYShsYXQpLHVuaXF1ZSguaWQpXSkpewogIGZvciAoayBpbiBjKCJkZHVyYXRpb24iLCJtYXhkZXB0aCIsImVmZmljaWVuY3kiLCAiZHJpZnRyYXRlIikpewogICAgaWYgKGsgPT0gImRyaWZ0cmF0ZSIpewogICAgICAjIHNldCBkYXRhc2V0IHVzZWQgdG8gcGxvdAogICAgICBkYXRhUGxvdCA9IHVuaXF1ZShkYXRhXzIwMThfZmlsdGVyICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAuW29yZGVyKGRhdGUpLF0gJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgIC5bLmlkPT1kYXRhXzIwMThfZmlsdGVyWyFpcy5uYShsYXQpLCB1bmlxdWUoLmlkKV1baV0gJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXZldHlwZSA9PSAiMjogZHJpZnQiICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIWlzLm5hKGdldChrKSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYygibGF0IiwgImxvbiIsIGspLCB3aXRoPUZBTFNFXSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgLlshaXNfb3V0bGllcihnZXQoaykpLF0pCiAgICAgICMgY29sb3IgcGFsZXR0ZSBjcmVhdGlvbgogICAgICBjb2xQYWwgPC0gY29sb3JOdW1lcmljKAogICAgICAgIHBhbGV0dGUgPSAiQnJCRyIsCiAgICAgICAgZG9tYWluID0gc2VxKC1kYXRhUGxvdFssbWF4KGFicyhkcmlmdHJhdGUpKV0sCiAgICAgICAgICAgICAgICAgICAgIGRhdGFQbG90WyxtYXgoYWJzKGRyaWZ0cmF0ZSkpXSwKICAgICAgICAgICAgICAgICAgICAgMC4xKQogICAgICApCiAgICB9IGVsc2UgewogICAgICAjIHNldCBkYXRhc2V0IHVzZWQgdG8gcGxvdAogICAgICBkYXRhUGxvdCA9IHVuaXF1ZShkYXRhXzIwMThfZmlsdGVyICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAuW29yZGVyKGRhdGUpLF0gJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgIC5bLmlkPT1kYXRhXzIwMThfZmlsdGVyWyFpcy5uYShsYXQpLCB1bmlxdWUoLmlkKV1baV0gJiAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGl2ZXR5cGUgIT0gIjI6IGRyaWZ0IiAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICFpcy5uYShnZXQoaykpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoImxhdCIsICJsb24iLCBrKSwgd2l0aD1GQUxTRV0gJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgIC5bIWlzX291dGxpZXIoZ2V0KGspKSxdKSAKICAgICAgIyBjb2xvciBwYWxldHRlIGNyZWF0aW9uCiAgICAgIGNvbFBhbCA8LSBjb2xvck51bWVyaWMoCiAgICAgICAgcGFsZXR0ZSA9ICJZbEduQnUiLAogICAgICAgIGRvbWFpbiA9IGRhdGFQbG90WyxnZXQoayldCiAgICAgICkKICAgIH0KICAgIAogICAgIyBhZGQgY29sb3IgdG8gZGF0YXNldAogICAgZGF0YVBsb3RbLCBjb2xvciA6PSBjb2xQYWwoZGF0YVBsb3RbLGdldChrKV0pXQogICAgIyBhZGQgc2l6ZSBjb2x1bW4KICAgIGRhdGFQbG90WywgcmFkaXVzIDo9IDNdCiAgICAjIG1hcmsgdGhlIGJlZ2lubmluZyBvZiB0aGUgdHJpcAogICAgZGF0YVBsb3RbMSwgYDo9YCAoY29sb3IgPSAiZ3JlZW4iLAogICAgICAgICAgICAgICAgICAgICAgcmFkaXVzID0gNCldCiAgICAjIG1hcmsgdGhlIGVuZCBvZiB0aGUgdHJpcAogICAgZGF0YVBsb3RbLk4sIGA6PWAgKGNvbG9yID0gInJlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgcmFkaXVzID0gNCldCiAgICAjIHJlb3JkZXIgdG8gbWFrZSB0aGUgZW5kIGFuZCB0aGUgYmVnaW5uaW5nIGluIGZyb250CiAgICBkYXRhUGxvdCA9IHJiaW5kKGRhdGFQbG90Wy0xLF0sZGF0YVBsb3RbMSxdKQogICAgIyBhZGQgbWFya2VycyB0byBtYXAKICAgIGdyYWRpZW50X21hcCA8LSBhZGRDaXJjbGVNYXJrZXJzKAogICAgICBtYXAgPSBncmFkaWVudF9tYXAsCiAgICAgIGRhdGEgPSBkYXRhUGxvdCwKICAgICAgbGF0ID0gfmxhdCwKICAgICAgbG5nID0gfmxvbiwKICAgICAgcmFkaXVzID0gfnJhZGl1cywKICAgICAgc3Ryb2tlID0gRkFMU0UsCiAgICAgIGNvbG9yID0gfmNvbG9yLAogICAgICBmaWxsT3BhY2l0eSA9IDEsCiAgICAgIGdyb3VwID0gcGFzdGUoZGF0YV8yMDE4X2ZpbHRlclssdW5pcXVlKC5pZCldW2ldLCAiLSIsIGspCiAgICApICU+JSAKICAgICAgYWRkTGVnZW5kKCJib3R0b21sZWZ0IiwgCiAgICAgICAgICAgICAgICBkYXRhID0gZGF0YVBsb3QsCiAgICAgICAgICAgICAgICBncm91cCA9IHBhc3RlKGRhdGFfMjAxOF9maWx0ZXJbLHVuaXF1ZSguaWQpXVtpXSwgIi0iLCBrKSwKICAgICAgICAgICAgICAgIHBhbCA9IGNvbFBhbCwgCiAgICAgICAgICAgICAgICB2YWx1ZXMgPSB+Z2V0KGspLAogICAgICAgICAgICAgICAgdGl0bGUgPSBrLAogICAgICAgICAgICAgICAgb3BhY2l0eSA9IDEKICAgICAgKQogICAgIyByZXRyaWV2ZSBncm91cHMKICAgIGdycHMgPSBjKGdycHMsIHBhc3RlKGRhdGFfMjAxOF9maWx0ZXJbLHVuaXF1ZSguaWQpXVtpXSwgIi0iLCBrKSkKICB9Cn0KCiMgYWRkIGxheWVyIGNvbnRyb2wKZ3JhZGllbnRfbWFwIDwtIGFkZExheWVyc0NvbnRyb2woCiAgbWFwID0gZ3JhZGllbnRfbWFwLAogIG92ZXJsYXlHcm91cHMgPSBncnBzLAogIG9wdGlvbnMgPSBsYXllcnNDb250cm9sT3B0aW9ucyhjb2xsYXBzZWQgPSBUUlVFKQopICU+JSBoaWRlR3JvdXAoZ3JwcykKYGBgCgpgYGB7ciBkYXRhLWV4cGxvcmF0aW9uLTIwMTgtNDUsIGZpZy5jYXA9IlRyYWNraW5nIGRhdGEgMjAxOCBpbmRpdmlkdWFscyAoZ3JlZW4gYW5kIHJlZCBkb3QgcmVzcGVjdGl2ZWx5IGluZGljYXRlIHRoZSBiZWdpbm5pbmcgYW5kIHRoZSBlbmQgb2YgZWFjaCB0cmlwKSIsIGZpZy53aWR0aD04fQojIGRpc3BsYXkKZ3JhZGllbnRfbWFwCmBgYAoK